improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
This commit is contained in:
parent
3617fe8b41
commit
4bd6b7aab1
157 changed files with 3290 additions and 8882 deletions
|
|
@ -1,639 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.testkit.ErrorFilter;
|
||||
import akka.testkit.EventFilter;
|
||||
import akka.testkit.TestEvent;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import docs.AbstractJavaTest;
|
||||
import org.scalatest.junit.JUnitSuite;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
import static docs.actor.Messages.Swap.Swap;
|
||||
import static akka.japi.Util.immutableSeq;
|
||||
|
||||
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 extends AbstractJavaTest {
|
||||
|
||||
public static Config config = ConfigFactory.parseString(
|
||||
"akka {\n" +
|
||||
" loggers = [\"akka.testkit.TestEventListener\"]\n" +
|
||||
" loglevel = \"WARNING\"\n" +
|
||||
" stdout-loglevel = \"WARNING\"\n" +
|
||||
"}\n"
|
||||
);
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
system = ActorSystem.create("ActorDocTest", config);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
Await.result(system.terminate(), 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
|
||||
public FirstActor() {
|
||||
receive(ReceiveBuilder.
|
||||
matchAny(x -> {
|
||||
sender().tell(x, self());
|
||||
}).build()
|
||||
);
|
||||
}
|
||||
//#plus-some-behavior
|
||||
}
|
||||
//#context-actorOf
|
||||
|
||||
static public abstract class SomeActor extends AbstractActor {
|
||||
//#receive-constructor
|
||||
public SomeActor() {
|
||||
receive(ReceiveBuilder.
|
||||
//#and-some-behavior
|
||||
match(String.class, s -> System.out.println(s.toLowerCase())).
|
||||
//#and-some-behavior
|
||||
build());
|
||||
}
|
||||
//#receive-constructor
|
||||
@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;
|
||||
receive(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;
|
||||
receive(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
|
||||
public SomeOtherActor() {
|
||||
receive(emptyBehavior());
|
||||
}
|
||||
//#props-factory
|
||||
}
|
||||
//#props-factory
|
||||
|
||||
public static class Hook extends AbstractActor {
|
||||
ActorRef target = null;
|
||||
public Hook() {
|
||||
receive(emptyBehavior());
|
||||
}
|
||||
//#preStart
|
||||
@Override
|
||||
public void preStart() {
|
||||
target = context().actorOf(Props.create(MyActor.class, "target"));
|
||||
}
|
||||
//#preStart
|
||||
//#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 {
|
||||
public ReplyException() {
|
||||
receive(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"));
|
||||
|
||||
public Manager() {
|
||||
receive(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 {
|
||||
public Cruncher() {
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("crunch", s -> { }).build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#swapper
|
||||
public class Swapper extends AbstractLoggingActor {
|
||||
public Swapper() {
|
||||
receive(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.terminate();
|
||||
}
|
||||
}
|
||||
//#swapper
|
||||
|
||||
|
||||
@Test
|
||||
public void creatingActorWithSystemActorOf() {
|
||||
//#system-actorOf
|
||||
// ActorSystem is a heavy object: create only one per application
|
||||
final ActorSystem system = ActorSystem.create("MySystem", config);
|
||||
final ActorRef myActor = system.actorOf(Props.create(FirstActor.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 {
|
||||
//#receive-timeout
|
||||
ActorRef target = context().system().deadLetters();
|
||||
//#receive-timeout
|
||||
public ReceiveTimeoutActor() {
|
||||
// To set an initial delay
|
||||
context().setReceiveTimeout(Duration.create("10 seconds"));
|
||||
|
||||
receive(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;
|
||||
|
||||
public HotSwapActor() {
|
||||
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();
|
||||
|
||||
receive(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 ActorWithProtocol() {
|
||||
receive(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");
|
||||
private ActorRef lastSender = system.deadLetters();
|
||||
|
||||
public WatchActor() {
|
||||
context().watch(child); // <-- this is the only call needed for registration
|
||||
|
||||
receive(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;
|
||||
|
||||
public Follower(){
|
||||
ActorSelection selection = context().actorSelection("/user/another");
|
||||
selection.tell(new Identify(identifyId), self());
|
||||
|
||||
receive(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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class NoReceiveActor extends AbstractActor {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noReceiveActor() {
|
||||
EventFilter ex1 = new ErrorFilter(ActorInitializationException.class);
|
||||
EventFilter[] ignoreExceptions = { ex1 };
|
||||
try {
|
||||
system.eventStream().publish(new TestEvent.Mute(immutableSeq(ignoreExceptions)));
|
||||
new JavaTestKit(system) {{
|
||||
final ActorRef victim = new EventFilter<ActorRef>(ActorInitializationException.class) {
|
||||
protected ActorRef run() {
|
||||
return system.actorOf(Props.create(NoReceiveActor.class), "victim");
|
||||
}
|
||||
}.message("Actor behavior has not been set with receive(...)").occurrences(1).exec();
|
||||
|
||||
assertEquals(true, victim.isTerminated());
|
||||
}};
|
||||
} finally {
|
||||
system.eventStream().publish(new TestEvent.UnMute(immutableSeq(ignoreExceptions)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultipleReceiveActor extends AbstractActor {
|
||||
public MultipleReceiveActor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, s1 -> s1.toLowerCase().equals("become"), s1 -> {
|
||||
sender().tell(s1.toUpperCase(), self());
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, s2 -> {
|
||||
sender().tell(s2.toLowerCase(), self());
|
||||
}).build()
|
||||
);
|
||||
}).
|
||||
match(String.class, s1 -> {
|
||||
sender().tell(s1.toUpperCase(), self());
|
||||
}).build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleReceiveActor() {
|
||||
EventFilter ex1 = new ErrorFilter(IllegalActorStateException.class);
|
||||
EventFilter[] ignoreExceptions = { ex1 };
|
||||
try {
|
||||
system.eventStream().publish(new TestEvent.Mute(immutableSeq(ignoreExceptions)));
|
||||
new JavaTestKit(system) {{
|
||||
new EventFilter<Boolean>(IllegalActorStateException.class) {
|
||||
protected Boolean run() {
|
||||
ActorRef victim = system.actorOf(Props.create(MultipleReceiveActor.class), "victim2");
|
||||
victim.tell("Foo", getRef());
|
||||
expectMsgEquals("FOO");
|
||||
victim.tell("bEcoMe", getRef());
|
||||
expectMsgEquals("BECOME");
|
||||
victim.tell("Foo", getRef());
|
||||
// if it's upper case, then the actor was restarted
|
||||
expectMsgEquals("FOO");
|
||||
return true;
|
||||
}
|
||||
}.message("Actor behavior has already been set with receive(...), " +
|
||||
"use context().become(...) to change it later").occurrences(1).exec();
|
||||
}};
|
||||
} finally {
|
||||
system.eventStream().publish(new TestEvent.UnMute(immutableSeq(ignoreExceptions)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#imports-data
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import akka.actor.ActorRef;
|
||||
//#imports-data
|
||||
|
||||
//#imports-actor
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.event.Logging;
|
||||
import akka.actor.UntypedActor;
|
||||
//#imports-actor
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import akka.testkit.TestProbe;
|
||||
import akka.testkit.AkkaSpec;
|
||||
import docs.AbstractJavaTest;
|
||||
|
||||
public class FSMDocTest extends AbstractJavaTest {
|
||||
|
||||
static
|
||||
//#data
|
||||
public final class SetTarget {
|
||||
final ActorRef ref;
|
||||
|
||||
public SetTarget(ActorRef ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
}
|
||||
|
||||
//#data
|
||||
static
|
||||
//#data
|
||||
public final class Queue {
|
||||
final Object o;
|
||||
|
||||
public Queue(Object o) {
|
||||
this.o = o;
|
||||
}
|
||||
}
|
||||
|
||||
//#data
|
||||
static
|
||||
//#data
|
||||
public final Object flush = new Object();
|
||||
|
||||
//#data
|
||||
static
|
||||
//#data
|
||||
public final class Batch {
|
||||
final List<Object> objects;
|
||||
|
||||
public Batch(List<Object> objects) {
|
||||
this.objects = objects;
|
||||
}
|
||||
}
|
||||
|
||||
//#data
|
||||
|
||||
static
|
||||
//#base
|
||||
public abstract class MyFSMBase extends UntypedActor {
|
||||
|
||||
/*
|
||||
* This is the mutable state of this state machine.
|
||||
*/
|
||||
protected enum State {
|
||||
IDLE, ACTIVE;
|
||||
}
|
||||
|
||||
private State state = State.IDLE;
|
||||
private ActorRef target;
|
||||
private List<Object> queue;
|
||||
|
||||
/*
|
||||
* Then come all the mutator methods:
|
||||
*/
|
||||
protected void init(ActorRef target) {
|
||||
this.target = target;
|
||||
queue = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
protected void setState(State s) {
|
||||
if (state != s) {
|
||||
transition(state, s);
|
||||
state = s;
|
||||
}
|
||||
}
|
||||
|
||||
protected void enqueue(Object o) {
|
||||
if (queue != null)
|
||||
queue.add(o);
|
||||
}
|
||||
|
||||
protected List<Object> drainQueue() {
|
||||
final List<Object> q = queue;
|
||||
if (q == null)
|
||||
throw new IllegalStateException("drainQueue(): not yet initialized");
|
||||
queue = new ArrayList<Object>();
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here are the interrogation methods:
|
||||
*/
|
||||
protected boolean isInitialized() {
|
||||
return target != null;
|
||||
}
|
||||
|
||||
protected State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
protected ActorRef getTarget() {
|
||||
if (target == null)
|
||||
throw new IllegalStateException("getTarget(): not yet initialized");
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
* And finally the callbacks (only one in this example: react to state change)
|
||||
*/
|
||||
abstract protected void transition(State old, State next);
|
||||
}
|
||||
|
||||
//#base
|
||||
|
||||
static
|
||||
//#actor
|
||||
public class MyFSM extends MyFSMBase {
|
||||
|
||||
private final LoggingAdapter log =
|
||||
Logging.getLogger(getContext().system(), this);
|
||||
|
||||
@Override
|
||||
public void onReceive(Object o) {
|
||||
|
||||
if (getState() == State.IDLE) {
|
||||
|
||||
if (o instanceof SetTarget)
|
||||
init(((SetTarget) o).ref);
|
||||
|
||||
else
|
||||
whenUnhandled(o);
|
||||
|
||||
} else if (getState() == State.ACTIVE) {
|
||||
|
||||
if (o == flush)
|
||||
setState(State.IDLE);
|
||||
|
||||
else
|
||||
whenUnhandled(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transition(State old, State next) {
|
||||
if (old == State.ACTIVE) {
|
||||
getTarget().tell(new Batch(drainQueue()), getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
private void whenUnhandled(Object o) {
|
||||
if (o instanceof Queue && isInitialized()) {
|
||||
enqueue(((Queue) o).o);
|
||||
setState(State.ACTIVE);
|
||||
|
||||
} else {
|
||||
log.warning("received unknown message {} in state {}", o, getState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#actor
|
||||
|
||||
ActorSystem system;
|
||||
|
||||
@org.junit.Before
|
||||
public void setUp() {
|
||||
system = ActorSystem.create("FSMSystem", AkkaSpec.testConf());
|
||||
}
|
||||
|
||||
@org.junit.Test
|
||||
public void mustBunch() {
|
||||
final ActorRef buncher = system.actorOf(Props.create(MyFSM.class));
|
||||
final TestProbe probe = new TestProbe(system);
|
||||
buncher.tell(new SetTarget(probe.ref()), ActorRef.noSender());
|
||||
buncher.tell(new Queue(1), ActorRef.noSender());
|
||||
buncher.tell(new Queue(2), ActorRef.noSender());
|
||||
buncher.tell(flush, ActorRef.noSender());
|
||||
buncher.tell(new Queue(3), ActorRef.noSender());
|
||||
final Batch b = probe.expectMsgClass(Batch.class);
|
||||
assert b.objects.size() == 2;
|
||||
assert b.objects.contains(1);
|
||||
assert b.objects.contains(2);
|
||||
}
|
||||
|
||||
@org.junit.After
|
||||
public void cleanup() {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#testkit
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.SupervisorStrategy;
|
||||
import static akka.actor.SupervisorStrategy.resume;
|
||||
import static akka.actor.SupervisorStrategy.restart;
|
||||
import static akka.actor.SupervisorStrategy.stop;
|
||||
import static akka.actor.SupervisorStrategy.escalate;
|
||||
import akka.actor.SupervisorStrategy.Directive;
|
||||
import akka.actor.OneForOneStrategy;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.Terminated;
|
||||
import akka.actor.UntypedActor;
|
||||
import docs.AbstractJavaTest;
|
||||
import scala.collection.immutable.Seq;
|
||||
import scala.concurrent.Await;
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import akka.testkit.TestProbe;
|
||||
|
||||
//#testkit
|
||||
import akka.testkit.ErrorFilter;
|
||||
import akka.testkit.EventFilter;
|
||||
import akka.testkit.TestEvent;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static akka.japi.Util.immutableSeq;
|
||||
import akka.japi.Function;
|
||||
import scala.Option;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.AfterClass;
|
||||
|
||||
//#testkit
|
||||
public class FaultHandlingTest extends AbstractJavaTest {
|
||||
//#testkit
|
||||
static
|
||||
//#supervisor
|
||||
public class Supervisor extends UntypedActor {
|
||||
|
||||
//#strategy
|
||||
private static SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(10, Duration.create("1 minute"),
|
||||
new Function<Throwable, Directive>() {
|
||||
@Override
|
||||
public Directive apply(Throwable t) {
|
||||
if (t instanceof ArithmeticException) {
|
||||
return resume();
|
||||
} else if (t instanceof NullPointerException) {
|
||||
return restart();
|
||||
} else if (t instanceof IllegalArgumentException) {
|
||||
return stop();
|
||||
} else {
|
||||
return escalate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#strategy
|
||||
|
||||
public void onReceive(Object o) {
|
||||
if (o instanceof Props) {
|
||||
getSender().tell(getContext().actorOf((Props) o), getSelf());
|
||||
} else {
|
||||
unhandled(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#supervisor
|
||||
|
||||
static
|
||||
//#supervisor2
|
||||
public class Supervisor2 extends UntypedActor {
|
||||
|
||||
//#strategy2
|
||||
private static SupervisorStrategy strategy = new OneForOneStrategy(10,
|
||||
Duration.create("1 minute"),
|
||||
new Function<Throwable, Directive>() {
|
||||
@Override
|
||||
public Directive apply(Throwable t) {
|
||||
if (t instanceof ArithmeticException) {
|
||||
return resume();
|
||||
} else if (t instanceof NullPointerException) {
|
||||
return restart();
|
||||
} else if (t instanceof IllegalArgumentException) {
|
||||
return stop();
|
||||
} else {
|
||||
return escalate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#strategy2
|
||||
|
||||
public void onReceive(Object o) {
|
||||
if (o instanceof Props) {
|
||||
getSender().tell(getContext().actorOf((Props) o), getSelf());
|
||||
} else {
|
||||
unhandled(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRestart(Throwable cause, Option<Object> msg) {
|
||||
// do not kill all children, which is the default here
|
||||
}
|
||||
}
|
||||
|
||||
//#supervisor2
|
||||
|
||||
static
|
||||
//#child
|
||||
public class Child extends UntypedActor {
|
||||
int state = 0;
|
||||
|
||||
public void onReceive(Object o) throws Exception {
|
||||
if (o instanceof Exception) {
|
||||
throw (Exception) o;
|
||||
} else if (o instanceof Integer) {
|
||||
state = (Integer) o;
|
||||
} else if (o.equals("get")) {
|
||||
getSender().tell(state, getSelf());
|
||||
} else {
|
||||
unhandled(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#child
|
||||
|
||||
//#testkit
|
||||
static ActorSystem system;
|
||||
Duration timeout = Duration.create(5, SECONDS);
|
||||
|
||||
@BeforeClass
|
||||
public static void start() {
|
||||
system = ActorSystem.create("FaultHandlingTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustEmploySupervisorStrategy() throws Exception {
|
||||
// code here
|
||||
//#testkit
|
||||
EventFilter ex1 = new ErrorFilter(ArithmeticException.class);
|
||||
EventFilter ex2 = new ErrorFilter(NullPointerException.class);
|
||||
EventFilter ex3 = new ErrorFilter(IllegalArgumentException.class);
|
||||
EventFilter ex4 = new ErrorFilter(Exception.class);
|
||||
EventFilter[] ignoreExceptions = { ex1, ex2, ex3, ex4 };
|
||||
Seq<EventFilter> seq = immutableSeq(ignoreExceptions);
|
||||
system.eventStream().publish(new TestEvent.Mute(seq));
|
||||
|
||||
//#create
|
||||
Props superprops = Props.create(Supervisor.class);
|
||||
ActorRef supervisor = system.actorOf(superprops, "supervisor");
|
||||
ActorRef child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
//#create
|
||||
|
||||
//#resume
|
||||
child.tell(42, ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
|
||||
child.tell(new ArithmeticException(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
|
||||
//#resume
|
||||
|
||||
//#restart
|
||||
child.tell(new NullPointerException(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
//#restart
|
||||
|
||||
//#stop
|
||||
final TestProbe probe = new TestProbe(system);
|
||||
probe.watch(child);
|
||||
child.tell(new IllegalArgumentException(), ActorRef.noSender());
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
//#stop
|
||||
|
||||
//#escalate-kill
|
||||
child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
probe.watch(child);
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
child.tell(new Exception(), ActorRef.noSender());
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
//#escalate-kill
|
||||
|
||||
//#escalate-restart
|
||||
superprops = Props.create(Supervisor2.class);
|
||||
supervisor = system.actorOf(superprops);
|
||||
child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
child.tell(23, ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(23);
|
||||
child.tell(new Exception(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
//#escalate-restart
|
||||
//#testkit
|
||||
}
|
||||
|
||||
}
|
||||
//#testkit
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#testkit
|
||||
import akka.actor.*;
|
||||
|
||||
import static akka.actor.SupervisorStrategy.resume;
|
||||
import static akka.actor.SupervisorStrategy.restart;
|
||||
import static akka.actor.SupervisorStrategy.stop;
|
||||
import static akka.actor.SupervisorStrategy.escalate;
|
||||
import akka.japi.pf.DeciderBuilder;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import org.scalatest.junit.JUnitSuite;
|
||||
import scala.PartialFunction;
|
||||
import scala.concurrent.Await;
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import akka.testkit.TestProbe;
|
||||
|
||||
//#testkit
|
||||
import akka.testkit.ErrorFilter;
|
||||
import akka.testkit.EventFilter;
|
||||
import akka.testkit.TestEvent;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static akka.japi.Util.immutableSeq;
|
||||
import scala.Option;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.AfterClass;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
//#testkit
|
||||
public class FaultHandlingTestJava8 extends JUnitSuite {
|
||||
//#testkit
|
||||
|
||||
public static Config config = ConfigFactory.parseString(
|
||||
"akka {\n" +
|
||||
" loggers = [\"akka.testkit.TestEventListener\"]\n" +
|
||||
" loglevel = \"WARNING\"\n" +
|
||||
" stdout-loglevel = \"WARNING\"\n" +
|
||||
"}\n");
|
||||
|
||||
static
|
||||
//#supervisor
|
||||
public class Supervisor extends AbstractActor {
|
||||
|
||||
//#strategy
|
||||
private static SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(10, Duration.create("1 minute"), DeciderBuilder.
|
||||
match(ArithmeticException.class, e -> resume()).
|
||||
match(NullPointerException.class, e -> restart()).
|
||||
match(IllegalArgumentException.class, e -> stop()).
|
||||
matchAny(o -> escalate()).build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#strategy
|
||||
|
||||
public Supervisor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Props.class, props -> {
|
||||
sender().tell(context().actorOf(props), self());
|
||||
}).build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//#supervisor
|
||||
|
||||
static
|
||||
//#supervisor2
|
||||
public class Supervisor2 extends AbstractActor {
|
||||
|
||||
//#strategy2
|
||||
private static SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(10, Duration.create("1 minute"), DeciderBuilder.
|
||||
match(ArithmeticException.class, e -> resume()).
|
||||
match(NullPointerException.class, e -> restart()).
|
||||
match(IllegalArgumentException.class, e -> stop()).
|
||||
matchAny(o -> escalate()).build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#strategy2
|
||||
|
||||
public Supervisor2() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Props.class, props -> {
|
||||
sender().tell(context().actorOf(props), self());
|
||||
}).build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRestart(Throwable cause, Option<Object> msg) {
|
||||
// do not kill all children, which is the default here
|
||||
}
|
||||
}
|
||||
|
||||
//#supervisor2
|
||||
|
||||
static
|
||||
//#child
|
||||
public class Child extends AbstractActor {
|
||||
int state = 0;
|
||||
|
||||
public Child() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Exception.class, exception -> { throw exception; }).
|
||||
match(Integer.class, i -> state = i).
|
||||
matchEquals("get", s -> sender().tell(state, self())).build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//#child
|
||||
|
||||
//#testkit
|
||||
static ActorSystem system;
|
||||
Duration timeout = Duration.create(5, SECONDS);
|
||||
|
||||
@BeforeClass
|
||||
public static void start() {
|
||||
system = ActorSystem.create("FaultHandlingTest", config);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustEmploySupervisorStrategy() throws Exception {
|
||||
// code here
|
||||
//#testkit
|
||||
EventFilter ex1 = new ErrorFilter(ArithmeticException.class);
|
||||
EventFilter ex2 = new ErrorFilter(NullPointerException.class);
|
||||
EventFilter ex3 = new ErrorFilter(IllegalArgumentException.class);
|
||||
EventFilter ex4 = new ErrorFilter(Exception.class);
|
||||
EventFilter[] ignoreExceptions = { ex1, ex2, ex3, ex4 };
|
||||
system.eventStream().publish(new TestEvent.Mute(immutableSeq(ignoreExceptions)));
|
||||
|
||||
//#create
|
||||
Props superprops = Props.create(Supervisor.class);
|
||||
ActorRef supervisor = system.actorOf(superprops, "supervisor");
|
||||
ActorRef child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
//#create
|
||||
|
||||
//#resume
|
||||
child.tell(42, ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
|
||||
child.tell(new ArithmeticException(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
|
||||
//#resume
|
||||
|
||||
//#restart
|
||||
child.tell(new NullPointerException(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
//#restart
|
||||
|
||||
//#stop
|
||||
final TestProbe probe = new TestProbe(system);
|
||||
probe.watch(child);
|
||||
child.tell(new IllegalArgumentException(), ActorRef.noSender());
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
//#stop
|
||||
|
||||
//#escalate-kill
|
||||
child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
probe.watch(child);
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
child.tell(new Exception(), ActorRef.noSender());
|
||||
probe.expectMsgClass(Terminated.class);
|
||||
//#escalate-kill
|
||||
|
||||
//#escalate-restart
|
||||
superprops = Props.create(Supervisor2.class);
|
||||
supervisor = system.actorOf(superprops);
|
||||
child = (ActorRef) Await.result(ask(supervisor,
|
||||
Props.create(Child.class), 5000), timeout);
|
||||
child.tell(23, ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(23);
|
||||
child.tell(new Exception(), ActorRef.noSender());
|
||||
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
|
||||
//#escalate-restart
|
||||
//#testkit
|
||||
}
|
||||
|
||||
}
|
||||
//#testkit
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.PoisonPill;
|
||||
import akka.actor.UntypedActor;
|
||||
|
||||
//#context-actorOf
|
||||
public class FirstUntypedActor extends UntypedActor {
|
||||
ActorRef myActor = getContext().actorOf(Props.create(MyActor.class), "myactor");
|
||||
|
||||
//#context-actorOf
|
||||
|
||||
public void onReceive(Object message) {
|
||||
myActor.forward(message, getContext());
|
||||
myActor.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.japi.Procedure;
|
||||
import akka.testkit.AkkaJUnitActorSystemResource;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import docs.AbstractJavaTest;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import scala.Option;
|
||||
|
||||
public class InitializationDocSpecJava extends AbstractJavaTest {
|
||||
|
||||
static public class PreStartInitExample extends UntypedActor {
|
||||
|
||||
public void onReceive(Object message) throws Exception {}
|
||||
|
||||
//#preStartInit
|
||||
@Override
|
||||
public void preStart() {
|
||||
// Initialize children here
|
||||
}
|
||||
|
||||
// Overriding postRestart to disable the call to preStart()
|
||||
// after restarts
|
||||
@Override
|
||||
public void postRestart(Throwable reason) {
|
||||
}
|
||||
|
||||
// The default implementation of preRestart() stops all the children
|
||||
// of the actor. To opt-out from stopping the children, we
|
||||
// have to override preRestart()
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Option<Object> message)
|
||||
throws Exception {
|
||||
// Keep the call to postStop(), but no stopping of children
|
||||
postStop();
|
||||
}
|
||||
//#preStartInit
|
||||
|
||||
}
|
||||
|
||||
public static class MessageInitExample extends UntypedActor {
|
||||
//#messageInit
|
||||
private String initializeMe = null;
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message.equals("init")) {
|
||||
initializeMe = "Up and running";
|
||||
getContext().become(new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object message) throws Exception {
|
||||
if (message.equals("U OK?"))
|
||||
getSender().tell(initializeMe, getSelf());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//#messageInit
|
||||
}
|
||||
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("InitializationDocSpecJava");
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
|
||||
@Test
|
||||
public void testIt() {
|
||||
|
||||
new JavaTestKit(system) {{
|
||||
ActorRef testactor = system.actorOf(Props.create(MessageInitExample.class), "testactor");
|
||||
String probe = "U OK?";
|
||||
|
||||
testactor.tell(probe, getRef());
|
||||
expectNoMsg();
|
||||
|
||||
testactor.tell("init", getRef());
|
||||
testactor.tell(probe, getRef());
|
||||
expectMsgEquals("Up and running");
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import docs.AbstractJavaTest;
|
||||
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 scala.concurrent.Await;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InitializationDocTest extends AbstractJavaTest {
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
system = ActorSystem.create("InitializationDocTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
Await.result(system.terminate(), Duration.create("5 seconds"));
|
||||
}
|
||||
|
||||
public static class MessageInitExample extends AbstractActor {
|
||||
private String initializeMe = null;
|
||||
|
||||
public MessageInitExample() {
|
||||
//#messageInit
|
||||
receive(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");
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
//#imports
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
|
||||
//#imports
|
||||
|
||||
//#my-actor
|
||||
public class MyJavaActor extends AbstractActor {
|
||||
private final LoggingAdapter log = Logging.getLogger(context().system(), this);
|
||||
|
||||
public MyJavaActor() {
|
||||
receive(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
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#receive-timeout
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ReceiveTimeout;
|
||||
import akka.actor.UntypedActor;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
public class MyReceiveTimeoutUntypedActor extends UntypedActor {
|
||||
//#receive-timeout
|
||||
ActorRef target = getContext().system().deadLetters();
|
||||
//#receive-timeout
|
||||
|
||||
public MyReceiveTimeoutUntypedActor() {
|
||||
// To set an initial delay
|
||||
getContext().setReceiveTimeout(Duration.create("30 seconds"));
|
||||
}
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("Hello")) {
|
||||
// To set in a response to a message
|
||||
getContext().setReceiveTimeout(Duration.create("1 second"));
|
||||
//#receive-timeout
|
||||
target = getSender();
|
||||
target.tell("Hello world", getSelf());
|
||||
//#receive-timeout
|
||||
} else if (message instanceof ReceiveTimeout) {
|
||||
// To turn it off
|
||||
getContext().setReceiveTimeout(Duration.Undefined());
|
||||
//#receive-timeout
|
||||
target.tell("timeout", getSelf());
|
||||
//#receive-timeout
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#receive-timeout
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#my-stopping-actor
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
public class MyStoppingActor extends UntypedActor {
|
||||
|
||||
ActorRef child = null;
|
||||
|
||||
// ... creation of child ...
|
||||
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message.equals("interrupt-child")) {
|
||||
context().stop(child);
|
||||
} else if (message.equals("done")) {
|
||||
context().stop(getSelf());
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#my-stopping-actor
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#my-untyped-actor
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
public class MyUntypedActor extends UntypedActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof String) {
|
||||
log.info("Received String message: {}", message);
|
||||
getSender().tell(message, getSelf());
|
||||
} else
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
//#my-untyped-actor
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.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();
|
||||
|
||||
public SampleActor() {
|
||||
receive(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
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import docs.AbstractJavaTest;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SampleActorTest extends AbstractJavaTest {
|
||||
|
||||
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();
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -11,10 +11,11 @@ import java.util.concurrent.TimeUnit;
|
|||
//#imports1
|
||||
|
||||
//#imports2
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.Cancellable;
|
||||
//#imports2
|
||||
|
||||
import docs.actorlambda.MyActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.testkit.AkkaSpec;
|
||||
|
|
@ -28,7 +29,7 @@ public class SchedulerDocTest extends AbstractJavaTest {
|
|||
AkkaSpec.testConf());
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
private ActorRef testActor = system.actorOf(Props.create(MyUntypedActor.class));
|
||||
private ActorRef testActor = system.actorOf(Props.create(MyActor.class));
|
||||
|
||||
@Test
|
||||
public void scheduleOneOffTask() {
|
||||
|
|
@ -51,14 +52,14 @@ public class SchedulerDocTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void scheduleRecurringTask() {
|
||||
//#schedule-recurring
|
||||
class Ticker extends UntypedActor {
|
||||
class Ticker extends AbstractActor {
|
||||
@Override
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("Tick")) {
|
||||
// Do someting
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("Tick", m -> {
|
||||
// Do someting
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,794 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
//#import-ask
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import static akka.pattern.Patterns.pipe;
|
||||
//#import-ask
|
||||
//#import-gracefulStop
|
||||
import static akka.pattern.Patterns.gracefulStop;
|
||||
//#import-gracefulStop
|
||||
|
||||
import akka.actor.PoisonPill;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.testkit.AkkaJUnitActorSystemResource;
|
||||
|
||||
import docs.AbstractJavaTest;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
//#import-gracefulStop
|
||||
import scala.concurrent.Await;
|
||||
//#import-ask
|
||||
import scala.concurrent.Future;
|
||||
import scala.concurrent.duration.Duration;
|
||||
//#import-ask
|
||||
//#import-gracefulStop
|
||||
//#import-indirect
|
||||
import akka.actor.Actor;
|
||||
//#import-indirect
|
||||
//#import-identify
|
||||
import akka.actor.ActorIdentity;
|
||||
//#import-identify
|
||||
import akka.actor.ActorKilledException;
|
||||
//#import-identify
|
||||
import akka.actor.ActorSelection;
|
||||
//#import-identify
|
||||
//#import-actorRef
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
//#import-actorRef
|
||||
//#import-identify
|
||||
import akka.actor.Identify;
|
||||
//#import-identify
|
||||
//#import-indirect
|
||||
import akka.actor.IndirectActorProducer;
|
||||
//#import-indirect
|
||||
import akka.actor.OneForOneStrategy;
|
||||
//#import-props
|
||||
import akka.actor.Props;
|
||||
import akka.japi.Creator;
|
||||
//#import-props
|
||||
import akka.actor.SupervisorStrategy;
|
||||
import akka.actor.SupervisorStrategy.Directive;
|
||||
//#import-terminated
|
||||
import akka.actor.Terminated;
|
||||
//#import-terminated
|
||||
//#import-untypedActor
|
||||
import akka.actor.UntypedActor;
|
||||
//#import-untypedActor
|
||||
//#import-stash
|
||||
import akka.actor.UntypedActorWithStash;
|
||||
//#import-stash
|
||||
//#import-ask
|
||||
import akka.dispatch.Futures;
|
||||
import akka.dispatch.Mapper;
|
||||
//#import-ask
|
||||
import akka.japi.Function;
|
||||
//#import-procedure
|
||||
import akka.japi.Procedure;
|
||||
//#import-procedure
|
||||
//#import-gracefulStop
|
||||
import akka.pattern.AskTimeoutException;
|
||||
//#import-gracefulStop
|
||||
import akka.pattern.Patterns;
|
||||
import akka.testkit.AkkaSpec;
|
||||
import akka.testkit.JavaTestKit;
|
||||
//#import-ask
|
||||
import akka.util.Timeout;
|
||||
//#import-ask
|
||||
|
||||
public class UntypedActorDocTest extends AbstractJavaTest {
|
||||
|
||||
@ClassRule
|
||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||
new AkkaJUnitActorSystemResource("UntypedActorDocTest", AkkaSpec.testConf());
|
||||
|
||||
private final ActorSystem system = actorSystemResource.getSystem();
|
||||
|
||||
//#creating-props-config
|
||||
static class MyActorC implements Creator<MyActor> {
|
||||
@Override public MyActor create() {
|
||||
return new MyActor("...");
|
||||
}
|
||||
}
|
||||
|
||||
//#creating-props-config
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void createProps() {
|
||||
//#creating-props-config
|
||||
Props props1 = Props.create(MyUntypedActor.class);
|
||||
Props props2 = Props.create(MyActor.class, "...");
|
||||
Props props3 = Props.create(new MyActorC());
|
||||
//#creating-props-config
|
||||
}
|
||||
|
||||
//#parametric-creator
|
||||
static class ParametricCreator<T extends MyActor> implements Creator<T> {
|
||||
@Override public T create() {
|
||||
// ... fabricate actor here
|
||||
//#parametric-creator
|
||||
return null;
|
||||
//#parametric-creator
|
||||
}
|
||||
}
|
||||
//#parametric-creator
|
||||
|
||||
@Test
|
||||
public void systemActorOf() {
|
||||
//#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(MyUntypedActor.class),
|
||||
"myactor");
|
||||
//#system-actorOf
|
||||
try {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
myActor.tell("hello", getRef());
|
||||
expectMsgEquals("hello");
|
||||
}
|
||||
};
|
||||
} finally {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextActorOf() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
//#context-actorOf
|
||||
class A extends UntypedActor {
|
||||
final ActorRef child =
|
||||
getContext().actorOf(Props.create(MyUntypedActor.class), "myChild");
|
||||
//#plus-some-behavior
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
getSender().tell(child, getSelf());
|
||||
}
|
||||
//#plus-some-behavior
|
||||
}
|
||||
//#context-actorOf
|
||||
final ActorRef top = system.actorOf(Props.create(A.class, this));
|
||||
top.tell("hello", getRef());
|
||||
final ActorRef child = expectMsgClass(ActorRef.class);
|
||||
child.tell("hello", getRef());
|
||||
expectMsgEquals("hello");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// this is just to make the test below a tiny fraction nicer
|
||||
private ActorSystem getContext() {
|
||||
return system;
|
||||
}
|
||||
|
||||
static
|
||||
//#creating-indirectly
|
||||
class DependencyInjector implements IndirectActorProducer {
|
||||
final Object applicationContext;
|
||||
final String beanName;
|
||||
|
||||
public DependencyInjector(Object applicationContext, String beanName) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Actor> actorClass() {
|
||||
return MyActor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyActor produce() {
|
||||
MyActor result;
|
||||
//#obtain-fresh-Actor-instance-from-DI-framework
|
||||
result = new MyActor((String) applicationContext);
|
||||
//#obtain-fresh-Actor-instance-from-DI-framework
|
||||
return result;
|
||||
}
|
||||
}
|
||||
//#creating-indirectly
|
||||
|
||||
@Test
|
||||
public void indirectActorOf() {
|
||||
final String applicationContext = "...";
|
||||
//#creating-indirectly
|
||||
|
||||
final ActorRef myActor = getContext().actorOf(
|
||||
Props.create(DependencyInjector.class, applicationContext, "MyActor"),
|
||||
"myactor3");
|
||||
//#creating-indirectly
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
myActor.tell("hello", getRef());
|
||||
expectMsgEquals("...");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void usingAsk() throws Exception {
|
||||
ActorRef myActor = system.actorOf(Props.create(MyAskActor.class, this), "myactor5");
|
||||
|
||||
//#using-ask
|
||||
Future<Object> future = Patterns.ask(myActor, "Hello", 1000);
|
||||
Object result = Await.result(future, Duration.create(1, TimeUnit.SECONDS));
|
||||
//#using-ask
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveTimeout() {
|
||||
final ActorRef myActor = system.actorOf(Props.create(MyReceiveTimeoutUntypedActor.class));
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
new Within(Duration.create(1, TimeUnit.SECONDS), Duration.create(1500,
|
||||
TimeUnit.MILLISECONDS)) {
|
||||
@Override
|
||||
protected void run() {
|
||||
myActor.tell("Hello", getRef());
|
||||
expectMsgEquals("Hello world");
|
||||
expectMsgEquals("timeout");
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usePoisonPill() {
|
||||
final ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class));
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
final ActorRef sender = getRef();
|
||||
//#poison-pill
|
||||
myActor.tell(akka.actor.PoisonPill.getInstance(), sender);
|
||||
//#poison-pill
|
||||
watch(myActor);
|
||||
expectTerminated(myActor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useKill() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
class Master extends UntypedActor {
|
||||
private SupervisorStrategy strategy = new OneForOneStrategy(-1,
|
||||
Duration.Undefined(), new Function<Throwable, Directive>() {
|
||||
@Override
|
||||
public Directive apply(Throwable thr) {
|
||||
if (thr instanceof ActorKilledException) {
|
||||
target.tell("killed", getSelf());
|
||||
getContext().stop(getSelf());
|
||||
return SupervisorStrategy.stop();
|
||||
}
|
||||
return SupervisorStrategy.escalate();
|
||||
}
|
||||
});
|
||||
final ActorRef target;
|
||||
ActorRef child;
|
||||
|
||||
//#preStart
|
||||
@Override
|
||||
public void preStart() {
|
||||
child = getContext().actorOf(Props.empty());
|
||||
}
|
||||
//#preStart
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public Master(ActorRef target) {
|
||||
this.target = target;
|
||||
|
||||
/*
|
||||
* Only compilation of `forward` is verified here.
|
||||
*/
|
||||
final Object result = "";
|
||||
//#forward
|
||||
target.forward(result, getContext());
|
||||
//#forward
|
||||
}
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
//#reply
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
Object result =
|
||||
//#calculate-result
|
||||
child;
|
||||
//#calculate-result
|
||||
|
||||
// do not forget the second argument!
|
||||
getSender().tell(result, getSelf());
|
||||
}
|
||||
//#reply
|
||||
|
||||
//#postStop
|
||||
@Override
|
||||
public void postStop() {
|
||||
//#clean-up-resources-here
|
||||
final String message = "stopped";
|
||||
//#tell
|
||||
// don’t forget to think about who is the sender (2nd argument)
|
||||
target.tell(message, getSelf());
|
||||
//#tell
|
||||
//#clean-up-resources-here
|
||||
}
|
||||
//#postStop
|
||||
}
|
||||
final ActorRef master = system.actorOf(Props.create(Master.class, this, getRef()));
|
||||
expectMsgEquals("");
|
||||
master.tell("", getRef());
|
||||
final ActorRef victim = expectMsgClass(ActorRef.class);
|
||||
//#kill
|
||||
victim.tell(akka.actor.Kill.getInstance(), ActorRef.noSender());
|
||||
//#kill
|
||||
expectMsgEquals("killed");
|
||||
expectMsgEquals("stopped");
|
||||
assert getLastSender().equals(master);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useBecome() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
ActorRef myActor = system.actorOf(Props.create(HotSwapActor.class));
|
||||
myActor.tell("foo", getRef());
|
||||
myActor.tell("bar", getRef());
|
||||
expectMsgEquals("I am already happy :-)");
|
||||
myActor.tell("bar", getRef());
|
||||
expectMsgEquals("I am already happy :-)");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useWatch() throws Exception {
|
||||
ActorRef myActor = system.actorOf(Props.create(WatchActor.class));
|
||||
Future<Object> future = Patterns.ask(myActor, "kill", 1000);
|
||||
assert Await.result(future, Duration.create("1 second")).equals("finished");
|
||||
}
|
||||
|
||||
// compilation test only
|
||||
public void compileSelections() {
|
||||
//#selection-local
|
||||
// will look up this absolute path
|
||||
getContext().actorSelection("/user/serviceA/actor");
|
||||
// will look up sibling beneath same supervisor
|
||||
getContext().actorSelection("../joe");
|
||||
//#selection-local
|
||||
|
||||
//#selection-wildcard
|
||||
// will look all children to serviceB with names starting with worker
|
||||
getContext().actorSelection("/user/serviceB/worker*");
|
||||
// will look up all siblings beneath same supervisor
|
||||
getContext().actorSelection("../*");
|
||||
//#selection-wildcard
|
||||
|
||||
//#selection-remote
|
||||
getContext().actorSelection("akka.tcp://app@otherhost:1234/user/serviceB");
|
||||
//#selection-remote
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useIdentify() throws Exception {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
ActorRef a = system.actorOf(Props.create(MyUntypedActor.class), "another");
|
||||
ActorRef b = system.actorOf(Props.create(Follower.class, getRef()));
|
||||
expectMsgEquals(a);
|
||||
system.stop(a);
|
||||
watch(b);
|
||||
expectTerminated(b);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usePatternsAskPipe() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
ActorRef actorA = system.actorOf(Props.create(MyUntypedActor.class));
|
||||
ActorRef actorB = system.actorOf(Props.create(MyUntypedActor.class));
|
||||
ActorRef actorC = getRef();
|
||||
|
||||
//#ask-pipe
|
||||
final Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
|
||||
|
||||
final ArrayList<Future<Object>> futures = new ArrayList<Future<Object>>();
|
||||
futures.add(ask(actorA, "request", 1000)); // using 1000ms timeout
|
||||
futures.add(ask(actorB, "another request", t)); // using timeout from
|
||||
// above
|
||||
|
||||
final Future<Iterable<Object>> aggregate = Futures.sequence(futures,
|
||||
system.dispatcher());
|
||||
|
||||
final Future<Result> transformed = aggregate.map(
|
||||
new Mapper<Iterable<Object>, Result>() {
|
||||
public Result apply(Iterable<Object> coll) {
|
||||
final Iterator<Object> it = coll.iterator();
|
||||
final String x = (String) it.next();
|
||||
final String s = (String) it.next();
|
||||
return new Result(x, s);
|
||||
}
|
||||
}, system.dispatcher());
|
||||
|
||||
pipe(transformed, system.dispatcher()).to(actorC);
|
||||
//#ask-pipe
|
||||
|
||||
expectMsgEquals(new Result("request", "another request"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static
|
||||
//#props-factory
|
||||
public class DemoActor extends UntypedActor {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public static Props props(final int magicNumber) {
|
||||
return Props.create(new Creator<DemoActor>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public DemoActor create() throws Exception {
|
||||
return new DemoActor(magicNumber);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final int magicNumber;
|
||||
|
||||
public DemoActor(int magicNumber) {
|
||||
this.magicNumber = magicNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
// some behavior here
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//#props-factory
|
||||
@Test
|
||||
public void demoActor() {
|
||||
//#props-factory
|
||||
system.actorOf(DemoActor.props(42), "demo");
|
||||
//#props-factory
|
||||
}
|
||||
|
||||
static
|
||||
//#messages-in-companion
|
||||
public class DemoMessagesActor extends UntypedActor {
|
||||
|
||||
static public class Greeting {
|
||||
private final String from;
|
||||
|
||||
public Greeting(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getGreeter() {
|
||||
return from;
|
||||
}
|
||||
}
|
||||
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof Greeting) {
|
||||
getSender().tell("Hello " + ((Greeting) message).getGreeter(), getSelf());
|
||||
} else
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
//#messages-in-companion
|
||||
|
||||
public static class MyActor extends UntypedActor {
|
||||
|
||||
final String s;
|
||||
|
||||
public MyActor(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public void onReceive(Object message) {
|
||||
getSender().tell(s, getSelf());
|
||||
}
|
||||
|
||||
/*
|
||||
* This section must be kept in sync with the actual Actor trait.
|
||||
*
|
||||
* BOYSCOUT RULE: whenever you read this, verify that!
|
||||
*/
|
||||
//#lifecycle-callbacks
|
||||
public void preStart() {
|
||||
}
|
||||
|
||||
public void preRestart(Throwable reason, scala.Option<Object> message) {
|
||||
for (ActorRef each : getContext().getChildren()) {
|
||||
getContext().unwatch(each);
|
||||
getContext().stop(each);
|
||||
}
|
||||
postStop();
|
||||
}
|
||||
|
||||
public void postRestart(Throwable reason) {
|
||||
preStart();
|
||||
}
|
||||
|
||||
public void postStop() {
|
||||
}
|
||||
//#lifecycle-callbacks
|
||||
}
|
||||
|
||||
public class MyAskActor extends UntypedActor {
|
||||
|
||||
public void onReceive(Object message) throws Exception {
|
||||
//#reply-exception
|
||||
try {
|
||||
String result = operation();
|
||||
getSender().tell(result, getSelf());
|
||||
} catch (Exception e) {
|
||||
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
|
||||
throw e;
|
||||
}
|
||||
//#reply-exception
|
||||
}
|
||||
|
||||
private String operation() {
|
||||
return "Hi";
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#gracefulStop-actor
|
||||
public class Manager extends UntypedActor {
|
||||
|
||||
public static final String SHUTDOWN = "shutdown";
|
||||
|
||||
ActorRef worker = getContext().watch(getContext().actorOf(
|
||||
Props.create(Cruncher.class), "worker"));
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("job")) {
|
||||
worker.tell("crunch", getSelf());
|
||||
} else if (message.equals(SHUTDOWN)) {
|
||||
worker.tell(PoisonPill.getInstance(), getSelf());
|
||||
getContext().become(shuttingDown);
|
||||
}
|
||||
}
|
||||
|
||||
Procedure<Object> shuttingDown = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object message) {
|
||||
if (message.equals("job")) {
|
||||
getSender().tell("service unavailable, shutting down", getSelf());
|
||||
} else if (message instanceof Terminated) {
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
//#gracefulStop-actor
|
||||
|
||||
static class Cruncher extends UntypedActor {
|
||||
public void onReceive(Object message) {
|
||||
// crunch...
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#hot-swap-actor
|
||||
public class HotSwapActor extends UntypedActor {
|
||||
|
||||
Procedure<Object> angry = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object message) {
|
||||
if (message.equals("bar")) {
|
||||
getSender().tell("I am already angry?", getSelf());
|
||||
} else if (message.equals("foo")) {
|
||||
getContext().become(happy);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Procedure<Object> happy = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object message) {
|
||||
if (message.equals("bar")) {
|
||||
getSender().tell("I am already happy :-)", getSelf());
|
||||
} else if (message.equals("foo")) {
|
||||
getContext().become(angry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("bar")) {
|
||||
getContext().become(angry);
|
||||
} else if (message.equals("foo")) {
|
||||
getContext().become(happy);
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#hot-swap-actor
|
||||
|
||||
static
|
||||
//#stash
|
||||
public class ActorWithProtocol extends UntypedActorWithStash {
|
||||
public void onReceive(Object msg) {
|
||||
if (msg.equals("open")) {
|
||||
unstashAll();
|
||||
getContext().become(new Procedure<Object>() {
|
||||
public void apply(Object msg) throws Exception {
|
||||
if (msg.equals("write")) {
|
||||
// do writing...
|
||||
} else if (msg.equals("close")) {
|
||||
unstashAll();
|
||||
getContext().unbecome();
|
||||
} else {
|
||||
stash();
|
||||
}
|
||||
}
|
||||
}, false); // add behavior on top instead of replacing
|
||||
} else {
|
||||
stash();
|
||||
}
|
||||
}
|
||||
}
|
||||
//#stash
|
||||
|
||||
static
|
||||
//#watch
|
||||
public class WatchActor extends UntypedActor {
|
||||
final ActorRef child = this.getContext().actorOf(Props.empty(), "child");
|
||||
{
|
||||
this.getContext().watch(child); // <-- the only call needed for registration
|
||||
}
|
||||
ActorRef lastSender = getContext().system().deadLetters();
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("kill")) {
|
||||
getContext().stop(child);
|
||||
lastSender = getSender();
|
||||
} else if (message instanceof Terminated) {
|
||||
final Terminated t = (Terminated) message;
|
||||
if (t.getActor() == child) {
|
||||
lastSender.tell("finished", getSelf());
|
||||
}
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#watch
|
||||
|
||||
static
|
||||
//#identify
|
||||
public class Follower extends UntypedActor {
|
||||
final String identifyId = "1";
|
||||
{
|
||||
ActorSelection selection =
|
||||
getContext().actorSelection("/user/another");
|
||||
selection.tell(new Identify(identifyId), getSelf());
|
||||
}
|
||||
ActorRef another;
|
||||
|
||||
//#test-omitted
|
||||
final ActorRef probe;
|
||||
public Follower(ActorRef probe) {
|
||||
this.probe = probe;
|
||||
}
|
||||
//#test-omitted
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof ActorIdentity) {
|
||||
ActorIdentity identity = (ActorIdentity) message;
|
||||
if (identity.correlationId().equals(identifyId)) {
|
||||
ActorRef ref = identity.getRef();
|
||||
if (ref == null)
|
||||
getContext().stop(getSelf());
|
||||
else {
|
||||
another = ref;
|
||||
getContext().watch(another);
|
||||
//#test-omitted
|
||||
probe.tell(ref, getSelf());
|
||||
//#test-omitted
|
||||
}
|
||||
}
|
||||
} else if (message instanceof Terminated) {
|
||||
final Terminated t = (Terminated) message;
|
||||
if (t.getActor().equals(another)) {
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#identify
|
||||
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor;
|
||||
|
||||
import static docs.actor.UntypedActorSwapper.Swap.SWAP;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.japi.Procedure;
|
||||
|
||||
//#swapper
|
||||
public class UntypedActorSwapper {
|
||||
|
||||
public static class Swap {
|
||||
public static Swap SWAP = new Swap();
|
||||
|
||||
private Swap() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Swapper extends UntypedActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message == SWAP) {
|
||||
log.info("Hi");
|
||||
getContext().become(new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object message) {
|
||||
log.info("Ho");
|
||||
getContext().unbecome(); // resets the latest 'become'
|
||||
}
|
||||
}, false); // this signals stacking of the new behavior
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef swap = system.actorOf(Props.create(Swapper.class));
|
||||
swap.tell(SWAP, ActorRef.noSender()); // logs Hi
|
||||
swap.tell(SWAP, ActorRef.noSender()); // logs Ho
|
||||
swap.tell(SWAP, ActorRef.noSender()); // logs Hi
|
||||
swap.tell(SWAP, ActorRef.noSender()); // logs Ho
|
||||
swap.tell(SWAP, ActorRef.noSender()); // logs Hi
|
||||
swap.tell(SWAP, ActorRef.noSender()); // logs Ho
|
||||
}
|
||||
|
||||
}
|
||||
//#swapper
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.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,
|
||||
(event, 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
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor.fsm;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import docs.AbstractJavaTest;
|
||||
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 extends AbstractJavaTest {
|
||||
|
||||
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
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.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
|
||||
}
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor.fsm;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import docs.AbstractJavaTest;
|
||||
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 extends AbstractJavaTest {
|
||||
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);
|
||||
assertThat(msg, CoreMatchers.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,489 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor.japi;
|
||||
|
||||
//#all
|
||||
//#imports
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.dispatch.Mapper;
|
||||
import akka.japi.Function;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import akka.util.Timeout;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
|
||||
import static akka.japi.Util.classTag;
|
||||
|
||||
import static akka.actor.SupervisorStrategy.restart;
|
||||
import static akka.actor.SupervisorStrategy.stop;
|
||||
import static akka.actor.SupervisorStrategy.escalate;
|
||||
import akka.actor.SupervisorStrategy.Directive;
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import static akka.pattern.Patterns.pipe;
|
||||
|
||||
import static docs.actor.japi.FaultHandlingDocSample.WorkerApi.*;
|
||||
import static docs.actor.japi.FaultHandlingDocSample.CounterServiceApi.*;
|
||||
import static docs.actor.japi.FaultHandlingDocSample.CounterApi.*;
|
||||
import static docs.actor.japi.FaultHandlingDocSample.StorageApi.*;
|
||||
|
||||
//#imports
|
||||
|
||||
public class FaultHandlingDocSample {
|
||||
|
||||
/**
|
||||
* Runs the sample
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Config config = ConfigFactory.parseString("akka.loglevel = DEBUG \n" +
|
||||
"akka.actor.debug.lifecycle = on");
|
||||
|
||||
ActorSystem system = ActorSystem.create("FaultToleranceSample", config);
|
||||
ActorRef worker = system.actorOf(Props.create(Worker.class), "worker");
|
||||
ActorRef listener = system.actorOf(Props.create(Listener.class), "listener");
|
||||
// start the work and listen on progress
|
||||
// note that the listener is used as sender of the tell,
|
||||
// i.e. it will receive replies from the worker
|
||||
worker.tell(Start, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens on progress from the worker and shuts down the system when enough
|
||||
* work has been done.
|
||||
*/
|
||||
public static class Listener extends UntypedActor {
|
||||
final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
// If we don't get any progress within 15 seconds then the service
|
||||
// is unavailable
|
||||
getContext().setReceiveTimeout(Duration.create("15 seconds"));
|
||||
}
|
||||
|
||||
public void onReceive(Object msg) {
|
||||
log.debug("received message {}", msg);
|
||||
if (msg instanceof Progress) {
|
||||
Progress progress = (Progress) msg;
|
||||
log.info("Current progress: {} %", progress.percent);
|
||||
if (progress.percent >= 100.0) {
|
||||
log.info("That's all, shutting down");
|
||||
getContext().system().terminate();
|
||||
}
|
||||
} else if (msg == ReceiveTimeout.getInstance()) {
|
||||
// No progress within 15 seconds, ServiceUnavailable
|
||||
log.error("Shutting down due to unavailable service");
|
||||
getContext().system().terminate();
|
||||
} else {
|
||||
unhandled(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface WorkerApi {
|
||||
public static final Object Start = "Start";
|
||||
public static final Object Do = "Do";
|
||||
|
||||
public static class Progress {
|
||||
public final double percent;
|
||||
|
||||
public Progress(double percent) {
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* Worker performs some work when it receives the Start message. It will
|
||||
* continuously notify the sender of the Start message of current Progress.
|
||||
* The Worker supervise the CounterService.
|
||||
*/
|
||||
public static class Worker extends UntypedActor {
|
||||
final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
final Timeout askTimeout = new Timeout(Duration.create(5, "seconds"));
|
||||
|
||||
// The sender of the initial Start message will continuously be notified
|
||||
// about progress
|
||||
ActorRef progressListener;
|
||||
final ActorRef counterService = getContext().actorOf(
|
||||
Props.create(CounterService.class), "counter");
|
||||
final int totalCount = 51;
|
||||
|
||||
// Stop the CounterService child if it throws ServiceUnavailable
|
||||
private static SupervisorStrategy strategy = new OneForOneStrategy(-1,
|
||||
Duration.Inf(), new Function<Throwable, Directive>() {
|
||||
@Override
|
||||
public Directive apply(Throwable t) {
|
||||
if (t instanceof ServiceUnavailable) {
|
||||
return stop();
|
||||
} else {
|
||||
return escalate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
public void onReceive(Object msg) {
|
||||
log.debug("received message {}", msg);
|
||||
if (msg.equals(Start) && progressListener == null) {
|
||||
progressListener = getSender();
|
||||
getContext().system().scheduler().schedule(
|
||||
Duration.Zero(), Duration.create(1, "second"), getSelf(), Do,
|
||||
getContext().dispatcher(), null
|
||||
);
|
||||
} else if (msg.equals(Do)) {
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
counterService.tell(new Increment(1), getSelf());
|
||||
|
||||
// Send current progress to the initial sender
|
||||
pipe(ask(counterService, GetCurrentCount, askTimeout)
|
||||
.mapTo(classTag(CurrentCount.class))
|
||||
.map(new Mapper<CurrentCount, Progress>() {
|
||||
public Progress apply(CurrentCount c) {
|
||||
return new Progress(100.0 * c.count / totalCount);
|
||||
}
|
||||
}, getContext().dispatcher()), getContext().dispatcher())
|
||||
.to(progressListener);
|
||||
} else {
|
||||
unhandled(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface CounterServiceApi {
|
||||
|
||||
public static final Object GetCurrentCount = "GetCurrentCount";
|
||||
|
||||
public static class CurrentCount {
|
||||
public final String key;
|
||||
public final long count;
|
||||
|
||||
public CurrentCount(String key, long count) {
|
||||
this.key = key;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s, %s)", getClass().getSimpleName(), key, count);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Increment {
|
||||
public final long n;
|
||||
|
||||
public Increment(long n) {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), n);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServiceUnavailable extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public ServiceUnavailable(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* Adds the value received in Increment message to a persistent counter.
|
||||
* Replies with CurrentCount when it is asked for CurrentCount. CounterService
|
||||
* supervise Storage and Counter.
|
||||
*/
|
||||
public static class CounterService extends UntypedActor {
|
||||
|
||||
// Reconnect message
|
||||
static final Object Reconnect = "Reconnect";
|
||||
|
||||
private static class SenderMsgPair {
|
||||
final ActorRef sender;
|
||||
final Object msg;
|
||||
|
||||
SenderMsgPair(ActorRef sender, Object msg) {
|
||||
this.msg = msg;
|
||||
this.sender = sender;
|
||||
}
|
||||
}
|
||||
|
||||
final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
final String key = getSelf().path().name();
|
||||
ActorRef storage;
|
||||
ActorRef counter;
|
||||
final List<SenderMsgPair> backlog = new ArrayList<SenderMsgPair>();
|
||||
final int MAX_BACKLOG = 10000;
|
||||
|
||||
// Restart the storage child when StorageException is thrown.
|
||||
// After 3 restarts within 5 seconds it will be stopped.
|
||||
private static SupervisorStrategy strategy = new OneForOneStrategy(3,
|
||||
Duration.create("5 seconds"), new Function<Throwable, Directive>() {
|
||||
@Override
|
||||
public Directive apply(Throwable t) {
|
||||
if (t instanceof StorageException) {
|
||||
return restart();
|
||||
} else {
|
||||
return escalate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
initStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* The child storage is restarted in case of failure, but after 3 restarts,
|
||||
* and still failing it will be stopped. Better to back-off than
|
||||
* continuously failing. When it has been stopped we will schedule a
|
||||
* Reconnect after a delay. Watch the child so we receive Terminated message
|
||||
* when it has been terminated.
|
||||
*/
|
||||
void initStorage() {
|
||||
storage = getContext().watch(getContext().actorOf(
|
||||
Props.create(Storage.class), "storage"));
|
||||
// Tell the counter, if any, to use the new storage
|
||||
if (counter != null)
|
||||
counter.tell(new UseStorage(storage), getSelf());
|
||||
// We need the initial value to be able to operate
|
||||
storage.tell(new Get(key), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
log.debug("received message {}", msg);
|
||||
if (msg instanceof Entry && ((Entry) msg).key.equals(key) &&
|
||||
counter == null) {
|
||||
// Reply from Storage of the initial value, now we can create the Counter
|
||||
final long value = ((Entry) msg).value;
|
||||
counter = getContext().actorOf(Props.create(Counter.class, key, value));
|
||||
// Tell the counter to use current storage
|
||||
counter.tell(new UseStorage(storage), getSelf());
|
||||
// and send the buffered backlog to the counter
|
||||
for (SenderMsgPair each : backlog) {
|
||||
counter.tell(each.msg, each.sender);
|
||||
}
|
||||
backlog.clear();
|
||||
} else if (msg instanceof Increment) {
|
||||
forwardOrPlaceInBacklog(msg);
|
||||
} else if (msg.equals(GetCurrentCount)) {
|
||||
forwardOrPlaceInBacklog(msg);
|
||||
} else if (msg instanceof Terminated) {
|
||||
// After 3 restarts the storage child is stopped.
|
||||
// We receive Terminated because we watch the child, see initStorage.
|
||||
storage = null;
|
||||
// Tell the counter that there is no storage for the moment
|
||||
counter.tell(new UseStorage(null), getSelf());
|
||||
// Try to re-establish storage after while
|
||||
getContext().system().scheduler().scheduleOnce(
|
||||
Duration.create(10, "seconds"), getSelf(), Reconnect,
|
||||
getContext().dispatcher(), null);
|
||||
} else if (msg.equals(Reconnect)) {
|
||||
// Re-establish storage after the scheduled delay
|
||||
initStorage();
|
||||
} else {
|
||||
unhandled(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void forwardOrPlaceInBacklog(Object msg) {
|
||||
// We need the initial value from storage before we can start delegate to
|
||||
// the counter. Before that we place the messages in a backlog, to be sent
|
||||
// to the counter when it is initialized.
|
||||
if (counter == null) {
|
||||
if (backlog.size() >= MAX_BACKLOG)
|
||||
throw new ServiceUnavailable("CounterService not available," +
|
||||
" lack of initial value");
|
||||
backlog.add(new SenderMsgPair(getSender(), msg));
|
||||
} else {
|
||||
counter.forward(msg, getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface CounterApi {
|
||||
public static class UseStorage {
|
||||
public final ActorRef storage;
|
||||
|
||||
public UseStorage(ActorRef storage) {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* The in memory count variable that will send current value to the Storage,
|
||||
* if there is any storage available at the moment.
|
||||
*/
|
||||
public static class Counter extends UntypedActor {
|
||||
final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
final String key;
|
||||
long count;
|
||||
ActorRef storage;
|
||||
|
||||
public Counter(String key, long initialValue) {
|
||||
this.key = key;
|
||||
this.count = initialValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
log.debug("received message {}", msg);
|
||||
if (msg instanceof UseStorage) {
|
||||
storage = ((UseStorage) msg).storage;
|
||||
storeCount();
|
||||
} else if (msg instanceof Increment) {
|
||||
count += ((Increment) msg).n;
|
||||
storeCount();
|
||||
} else if (msg.equals(GetCurrentCount)) {
|
||||
getSender().tell(new CurrentCount(key, count), getSelf());
|
||||
} else {
|
||||
unhandled(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void storeCount() {
|
||||
// Delegate dangerous work, to protect our valuable state.
|
||||
// We can continue without storage.
|
||||
if (storage != null) {
|
||||
storage.tell(new Store(new Entry(key, count)), getSelf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface StorageApi {
|
||||
|
||||
public static class Store {
|
||||
public final Entry entry;
|
||||
|
||||
public Store(Entry entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Entry {
|
||||
public final String key;
|
||||
public final long value;
|
||||
|
||||
public Entry(String key, long value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s, %s)", getClass().getSimpleName(), key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Get {
|
||||
public final String key;
|
||||
|
||||
public Get(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), key);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StorageException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public StorageException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* Saves key/value pairs to persistent storage when receiving Store message.
|
||||
* Replies with current value when receiving Get message. Will throw
|
||||
* StorageException if the underlying data store is out of order.
|
||||
*/
|
||||
public static class Storage extends UntypedActor {
|
||||
|
||||
final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
final DummyDB db = DummyDB.instance;
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
log.debug("received message {}", msg);
|
||||
if (msg instanceof Store) {
|
||||
Store store = (Store) msg;
|
||||
db.save(store.entry.key, store.entry.value);
|
||||
} else if (msg instanceof Get) {
|
||||
Get get = (Get) msg;
|
||||
Long value = db.load(get.key);
|
||||
getSender().tell(new Entry(get.key, value == null ?
|
||||
Long.valueOf(0L) : value), getSelf());
|
||||
} else {
|
||||
unhandled(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#dummydb
|
||||
public static class DummyDB {
|
||||
public static final DummyDB instance = new DummyDB();
|
||||
private final Map<String, Long> db = new HashMap<String, Long>();
|
||||
|
||||
private DummyDB() {
|
||||
}
|
||||
|
||||
public synchronized void save(String key, Long value) throws StorageException {
|
||||
if (11 <= value && value <= 14)
|
||||
throw new StorageException("Simulated store failure " + value);
|
||||
db.put(key, value);
|
||||
}
|
||||
|
||||
public synchronized Long load(String key) throws StorageException {
|
||||
return db.get(key);
|
||||
}
|
||||
}
|
||||
//#dummydb
|
||||
}
|
||||
//#all
|
||||
|
|
@ -1,470 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actor.japi;
|
||||
|
||||
//#all
|
||||
//#imports
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.dispatch.Mapper;
|
||||
import akka.event.LoggingReceive;
|
||||
import akka.japi.pf.DeciderBuilder;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.util.Timeout;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
import static akka.japi.Util.classTag;
|
||||
import static akka.actor.SupervisorStrategy.resume;
|
||||
import static akka.actor.SupervisorStrategy.restart;
|
||||
import static akka.actor.SupervisorStrategy.stop;
|
||||
import static akka.actor.SupervisorStrategy.escalate;
|
||||
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import static akka.pattern.Patterns.pipe;
|
||||
|
||||
import static docs.actor.japi.FaultHandlingDocSample.WorkerApi.*;
|
||||
import static docs.actor.japi.FaultHandlingDocSample.CounterServiceApi.*;
|
||||
import static docs.actor.japi.FaultHandlingDocSample.CounterApi.*;
|
||||
import static docs.actor.japi.FaultHandlingDocSample.StorageApi.*;
|
||||
|
||||
//#imports
|
||||
|
||||
public class FaultHandlingDocSampleJava8 {
|
||||
|
||||
/**
|
||||
* Runs the sample
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Config config = ConfigFactory.parseString(
|
||||
"akka.loglevel = \"DEBUG\"\n" +
|
||||
"akka.actor.debug {\n" +
|
||||
" receive = on\n" +
|
||||
" lifecycle = on\n" +
|
||||
"}\n");
|
||||
|
||||
ActorSystem system = ActorSystem.create("FaultToleranceSample", config);
|
||||
ActorRef worker = system.actorOf(Props.create(Worker.class), "worker");
|
||||
ActorRef listener = system.actorOf(Props.create(Listener.class), "listener");
|
||||
// start the work and listen on progress
|
||||
// note that the listener is used as sender of the tell,
|
||||
// i.e. it will receive replies from the worker
|
||||
worker.tell(Start, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens on progress from the worker and shuts down the system when enough
|
||||
* work has been done.
|
||||
*/
|
||||
public static class Listener extends AbstractLoggingActor {
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
// If we don't get any progress within 15 seconds then the service
|
||||
// is unavailable
|
||||
context().setReceiveTimeout(Duration.create("15 seconds"));
|
||||
}
|
||||
|
||||
public Listener() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
match(Progress.class, progress -> {
|
||||
log().info("Current progress: {} %", progress.percent);
|
||||
if (progress.percent >= 100.0) {
|
||||
log().info("That's all, shutting down");
|
||||
context().system().shutdown();
|
||||
}
|
||||
}).
|
||||
matchEquals(ReceiveTimeout.getInstance(), x -> {
|
||||
// No progress within 15 seconds, ServiceUnavailable
|
||||
log().error("Shutting down due to unavailable service");
|
||||
context().system().shutdown();
|
||||
}).build(), context()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface WorkerApi {
|
||||
public static final Object Start = "Start";
|
||||
public static final Object Do = "Do";
|
||||
|
||||
public static class Progress {
|
||||
public final double percent;
|
||||
|
||||
public Progress(double percent) {
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* Worker performs some work when it receives the Start message. It will
|
||||
* continuously notify the sender of the Start message of current Progress.
|
||||
* The Worker supervise the CounterService.
|
||||
*/
|
||||
public static class Worker extends AbstractLoggingActor {
|
||||
final Timeout askTimeout = new Timeout(Duration.create(5, "seconds"));
|
||||
|
||||
// The sender of the initial Start message will continuously be notified
|
||||
// about progress
|
||||
ActorRef progressListener;
|
||||
final ActorRef counterService = context().actorOf(
|
||||
Props.create(CounterService.class), "counter");
|
||||
final int totalCount = 51;
|
||||
|
||||
// Stop the CounterService child if it throws ServiceUnavailable
|
||||
private static final SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(DeciderBuilder.
|
||||
match(ServiceUnavailable.class, e -> stop()).
|
||||
matchAny(o -> escalate()).build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
public Worker() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
matchEquals(Start, x -> progressListener == null, x -> {
|
||||
progressListener = sender();
|
||||
context().system().scheduler().schedule(
|
||||
Duration.Zero(), Duration.create(1, "second"), self(), Do,
|
||||
context().dispatcher(), null
|
||||
);
|
||||
}).
|
||||
matchEquals(Do, x -> {
|
||||
counterService.tell(new Increment(1), self());
|
||||
counterService.tell(new Increment(1), self());
|
||||
counterService.tell(new Increment(1), self());
|
||||
// Send current progress to the initial sender
|
||||
pipe(ask(counterService, GetCurrentCount, askTimeout)
|
||||
.mapTo(classTag(CurrentCount.class))
|
||||
.map(new Mapper<CurrentCount, Progress>() {
|
||||
public Progress apply(CurrentCount c) {
|
||||
return new Progress(100.0 * c.count / totalCount);
|
||||
}
|
||||
}, context().dispatcher()), context().dispatcher())
|
||||
.to(progressListener);
|
||||
}).build(), context())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface CounterServiceApi {
|
||||
|
||||
public static final Object GetCurrentCount = "GetCurrentCount";
|
||||
|
||||
public static class CurrentCount {
|
||||
public final String key;
|
||||
public final long count;
|
||||
|
||||
public CurrentCount(String key, long count) {
|
||||
this.key = key;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s, %s)", getClass().getSimpleName(), key, count);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Increment {
|
||||
public final long n;
|
||||
|
||||
public Increment(long n) {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), n);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServiceUnavailable extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public ServiceUnavailable(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* Adds the value received in Increment message to a persistent counter.
|
||||
* Replies with CurrentCount when it is asked for CurrentCount. CounterService
|
||||
* supervise Storage and Counter.
|
||||
*/
|
||||
public static class CounterService extends AbstractLoggingActor {
|
||||
|
||||
// Reconnect message
|
||||
static final Object Reconnect = "Reconnect";
|
||||
|
||||
private static class SenderMsgPair {
|
||||
final ActorRef sender;
|
||||
final Object msg;
|
||||
|
||||
SenderMsgPair(ActorRef sender, Object msg) {
|
||||
this.msg = msg;
|
||||
this.sender = sender;
|
||||
}
|
||||
}
|
||||
|
||||
final String key = self().path().name();
|
||||
ActorRef storage;
|
||||
ActorRef counter;
|
||||
final List<SenderMsgPair> backlog = new ArrayList<>();
|
||||
final int MAX_BACKLOG = 10000;
|
||||
|
||||
// Restart the storage child when StorageException is thrown.
|
||||
// After 3 restarts within 5 seconds it will be stopped.
|
||||
private static final SupervisorStrategy strategy =
|
||||
new OneForOneStrategy(3, Duration.create("5 seconds"), DeciderBuilder.
|
||||
match(StorageException.class, e -> restart()).
|
||||
matchAny(o -> escalate()).build());
|
||||
|
||||
@Override
|
||||
public SupervisorStrategy supervisorStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
initStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* The child storage is restarted in case of failure, but after 3 restarts,
|
||||
* and still failing it will be stopped. Better to back-off than
|
||||
* continuously failing. When it has been stopped we will schedule a
|
||||
* Reconnect after a delay. Watch the child so we receive Terminated message
|
||||
* when it has been terminated.
|
||||
*/
|
||||
void initStorage() {
|
||||
storage = context().watch(context().actorOf(
|
||||
Props.create(Storage.class), "storage"));
|
||||
// Tell the counter, if any, to use the new storage
|
||||
if (counter != null)
|
||||
counter.tell(new UseStorage(storage), self());
|
||||
// We need the initial value to be able to operate
|
||||
storage.tell(new Get(key), self());
|
||||
}
|
||||
|
||||
public CounterService() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
match(Entry.class, entry -> entry.key.equals(key) && counter == null, entry -> {
|
||||
// Reply from Storage of the initial value, now we can create the Counter
|
||||
final long value = entry.value;
|
||||
counter = context().actorOf(Props.create(Counter.class, key, value));
|
||||
// Tell the counter to use current storage
|
||||
counter.tell(new UseStorage(storage), self());
|
||||
// and send the buffered backlog to the counter
|
||||
for (SenderMsgPair each : backlog) {
|
||||
counter.tell(each.msg, each.sender);
|
||||
}
|
||||
backlog.clear();
|
||||
}).
|
||||
match(Increment.class, increment -> {
|
||||
forwardOrPlaceInBacklog(increment);
|
||||
}).
|
||||
matchEquals(GetCurrentCount, gcc -> {
|
||||
forwardOrPlaceInBacklog(gcc);
|
||||
}).
|
||||
match(Terminated.class, o -> {
|
||||
// After 3 restarts the storage child is stopped.
|
||||
// We receive Terminated because we watch the child, see initStorage.
|
||||
storage = null;
|
||||
// Tell the counter that there is no storage for the moment
|
||||
counter.tell(new UseStorage(null), self());
|
||||
// Try to re-establish storage after while
|
||||
context().system().scheduler().scheduleOnce(
|
||||
Duration.create(10, "seconds"), self(), Reconnect,
|
||||
context().dispatcher(), null);
|
||||
}).
|
||||
matchEquals(Reconnect, o -> {
|
||||
// Re-establish storage after the scheduled delay
|
||||
initStorage();
|
||||
}).build(), context())
|
||||
);
|
||||
}
|
||||
|
||||
void forwardOrPlaceInBacklog(Object msg) {
|
||||
// We need the initial value from storage before we can start delegate to
|
||||
// the counter. Before that we place the messages in a backlog, to be sent
|
||||
// to the counter when it is initialized.
|
||||
if (counter == null) {
|
||||
if (backlog.size() >= MAX_BACKLOG)
|
||||
throw new ServiceUnavailable("CounterService not available," +
|
||||
" lack of initial value");
|
||||
backlog.add(new SenderMsgPair(sender(), msg));
|
||||
} else {
|
||||
counter.forward(msg, context());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface CounterApi {
|
||||
public static class UseStorage {
|
||||
public final ActorRef storage;
|
||||
|
||||
public UseStorage(ActorRef storage) {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* The in memory count variable that will send current value to the Storage,
|
||||
* if there is any storage available at the moment.
|
||||
*/
|
||||
public static class Counter extends AbstractLoggingActor {
|
||||
final String key;
|
||||
long count;
|
||||
ActorRef storage;
|
||||
|
||||
public Counter(String key, long initialValue) {
|
||||
this.key = key;
|
||||
this.count = initialValue;
|
||||
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
match(UseStorage.class, useStorage -> {
|
||||
storage = useStorage.storage;
|
||||
storeCount();
|
||||
}).
|
||||
match(Increment.class, increment -> {
|
||||
count += increment.n;
|
||||
storeCount();
|
||||
}).
|
||||
matchEquals(GetCurrentCount, gcc -> {
|
||||
sender().tell(new CurrentCount(key, count), self());
|
||||
}).build(), context())
|
||||
);
|
||||
}
|
||||
|
||||
void storeCount() {
|
||||
// Delegate dangerous work, to protect our valuable state.
|
||||
// We can continue without storage.
|
||||
if (storage != null) {
|
||||
storage.tell(new Store(new Entry(key, count)), self());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
public interface StorageApi {
|
||||
|
||||
public static class Store {
|
||||
public final Entry entry;
|
||||
|
||||
public Store(Entry entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Entry {
|
||||
public final String key;
|
||||
public final long value;
|
||||
|
||||
public Entry(String key, long value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s, %s)", getClass().getSimpleName(), key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Get {
|
||||
public final String key;
|
||||
|
||||
public Get(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", getClass().getSimpleName(), key);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StorageException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public StorageException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#messages
|
||||
|
||||
/**
|
||||
* Saves key/value pairs to persistent storage when receiving Store message.
|
||||
* Replies with current value when receiving Get message. Will throw
|
||||
* StorageException if the underlying data store is out of order.
|
||||
*/
|
||||
public static class Storage extends AbstractLoggingActor {
|
||||
|
||||
final DummyDB db = DummyDB.instance;
|
||||
|
||||
public Storage() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
match(Store.class, store -> {
|
||||
db.save(store.entry.key, store.entry.value);
|
||||
}).
|
||||
match(Get.class, get -> {
|
||||
Long value = db.load(get.key);
|
||||
sender().tell(new Entry(get.key, value == null ?
|
||||
Long.valueOf(0L) : value), self());
|
||||
}).build(), context())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//#dummydb
|
||||
public static class DummyDB {
|
||||
public static final DummyDB instance = new DummyDB();
|
||||
private final Map<String, Long> db = new HashMap<String, Long>();
|
||||
|
||||
private DummyDB() {
|
||||
}
|
||||
|
||||
public synchronized void save(String key, Long value) throws StorageException {
|
||||
if (11 <= value && value <= 14)
|
||||
throw new StorageException("Simulated store failure " + value);
|
||||
db.put(key, value);
|
||||
}
|
||||
|
||||
public synchronized Long load(String key) throws StorageException {
|
||||
return db.get(key);
|
||||
}
|
||||
}
|
||||
//#dummydb
|
||||
}
|
||||
//#all
|
||||
|
|
@ -12,19 +12,23 @@ import akka.testkit.TestEvent;
|
|||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import docs.AbstractJavaTest;
|
||||
import docs.actor.ActorDocTest.FirstActor;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
import static docs.actorlambda.Messages.Swap.Swap;
|
||||
import static docs.actorlambda.Messages.*;
|
||||
import static akka.japi.Util.immutableSeq;
|
||||
import akka.actor.CoordinatedShutdown;
|
||||
import static akka.pattern.PatternsCS.ask;
|
||||
|
||||
import akka.util.Timeout;
|
||||
import akka.Done;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import akka.testkit.TestActors;
|
||||
import akka.dispatch.Mapper;
|
||||
import akka.dispatch.Futures;
|
||||
import akka.util.Timeout;
|
||||
|
||||
import akka.testkit.JavaTestKit;
|
||||
import org.junit.AfterClass;
|
||||
|
|
@ -44,13 +48,25 @@ import akka.actor.ActorIdentity;
|
|||
import akka.actor.ActorSelection;
|
||||
import akka.actor.Identify;
|
||||
//#import-identify
|
||||
//#import-graceFulStop
|
||||
//#import-ask
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import static akka.pattern.Patterns.pipe;
|
||||
import akka.dispatch.Futures;
|
||||
import akka.dispatch.Mapper;
|
||||
import akka.util.Timeout;
|
||||
//#import-ask
|
||||
//#import-gracefulStop
|
||||
import akka.pattern.AskTimeoutException;
|
||||
import scala.concurrent.Await;
|
||||
import scala.concurrent.duration.Duration;
|
||||
//#import-ask
|
||||
import scala.concurrent.Future;
|
||||
import static akka.pattern.Patterns.gracefulStop;
|
||||
//#import-graceFulStop
|
||||
//#import-ask
|
||||
//#import-gracefulStop
|
||||
//#import-terminated
|
||||
import akka.actor.Terminated;
|
||||
//#import-terminated
|
||||
|
||||
public class ActorDocTest extends AbstractJavaTest {
|
||||
|
||||
|
|
@ -71,49 +87,111 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
Await.ready(system.terminate(), Duration.create("5 seconds"));
|
||||
Await.ready(system.terminate(), Duration.create(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
static
|
||||
//#context-actorOf
|
||||
public class FirstActor extends AbstractActor {
|
||||
final ActorRef child = context().actorOf(Props.create(MyActor.class), "myChild");
|
||||
final ActorRef child = getContext().actorOf(Props.create(MyActor.class), "myChild");
|
||||
|
||||
//#plus-some-behavior
|
||||
public FirstActor() {
|
||||
receive(ReceiveBuilder.
|
||||
matchAny(x -> {
|
||||
sender().tell(x, self());
|
||||
}).build()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(x -> sender().tell(x, self()))
|
||||
.build();
|
||||
}
|
||||
//#plus-some-behavior
|
||||
}
|
||||
//#context-actorOf
|
||||
|
||||
static public abstract class SomeActor extends AbstractActor {
|
||||
//#receive-constructor
|
||||
public SomeActor() {
|
||||
receive(ReceiveBuilder.
|
||||
//#and-some-behavior
|
||||
match(String.class, s -> System.out.println(s.toLowerCase())).
|
||||
//#and-some-behavior
|
||||
build());
|
||||
}
|
||||
//#receive-constructor
|
||||
static public class SomeActor extends AbstractActor {
|
||||
//#createReceive
|
||||
@Override
|
||||
//#receive
|
||||
public abstract PartialFunction<Object, BoxedUnit> receive();
|
||||
//#receive
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, s -> System.out.println(s.toLowerCase()))
|
||||
.build();
|
||||
}
|
||||
//#createReceive
|
||||
}
|
||||
|
||||
static
|
||||
//#well-structured
|
||||
public class WellStructuredActor extends AbstractActor {
|
||||
|
||||
public static class Msg1 {}
|
||||
public static class Msg2 {}
|
||||
public static class Msg3 {}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Msg1.class, this::receiveMsg1)
|
||||
.match(Msg2.class, this::receiveMsg2)
|
||||
.match(Msg3.class, this::receiveMsg3)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void receiveMsg1(Msg1 msg) {
|
||||
// actual work
|
||||
}
|
||||
|
||||
private void receiveMsg2(Msg2 msg) {
|
||||
// actual work
|
||||
}
|
||||
|
||||
private void receiveMsg3(Msg3 msg) {
|
||||
// actual work
|
||||
}
|
||||
}
|
||||
//#well-structured
|
||||
|
||||
static
|
||||
//#optimized
|
||||
public class OptimizedActor extends UntypedAbstractActor {
|
||||
|
||||
public static class Msg1 {}
|
||||
public static class Msg2 {}
|
||||
public static class Msg3 {}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof Msg1)
|
||||
receiveMsg1((Msg1) msg);
|
||||
else if (msg instanceof Msg1)
|
||||
receiveMsg2((Msg2) msg);
|
||||
else if (msg instanceof Msg3)
|
||||
receiveMsg3((Msg3) msg);
|
||||
else
|
||||
unhandled(msg);
|
||||
}
|
||||
|
||||
private void receiveMsg1(Msg1 msg) {
|
||||
// actual work
|
||||
}
|
||||
|
||||
private void receiveMsg2(Msg2 msg) {
|
||||
// actual work
|
||||
}
|
||||
|
||||
private void receiveMsg3(Msg3 msg) {
|
||||
// actual work
|
||||
}
|
||||
}
|
||||
//#optimized
|
||||
|
||||
static public class ActorWithArgs extends AbstractActor {
|
||||
private final String args;
|
||||
|
||||
ActorWithArgs(String args) {
|
||||
public ActorWithArgs(String args) {
|
||||
this.args = args;
|
||||
receive(ReceiveBuilder.
|
||||
matchAny(x -> { }).build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().matchAny(x -> { }).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,14 +211,18 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
private final Integer magicNumber;
|
||||
|
||||
DemoActor(Integer magicNumber) {
|
||||
|
||||
public DemoActor(Integer magicNumber) {
|
||||
this.magicNumber = magicNumber;
|
||||
receive(ReceiveBuilder.
|
||||
match(Integer.class, i -> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Integer.class, i -> {
|
||||
sender().tell(i + magicNumber, self());
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,11 +231,12 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
//#props-factory
|
||||
public class SomeOtherActor extends AbstractActor {
|
||||
// Props(new DemoActor(42)) would not be safe
|
||||
ActorRef demoActor = context().actorOf(DemoActor.props(42), "demo");
|
||||
ActorRef demoActor = getContext().actorOf(DemoActor.props(42), "demo");
|
||||
// ...
|
||||
//#props-factory
|
||||
public SomeOtherActor() {
|
||||
receive(emptyBehavior());
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
//#props-factory
|
||||
}
|
||||
|
|
@ -174,26 +257,65 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
return from;
|
||||
}
|
||||
}
|
||||
|
||||
DemoMessagesActor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Greeting.class, g -> {
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Greeting.class, g -> {
|
||||
log().info("I was greeted by {}", g.getGreeter());
|
||||
}).build()
|
||||
);
|
||||
};
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#messages-in-companion
|
||||
|
||||
|
||||
public static class LifecycleMethods extends AbstractActor {
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
|
||||
/*
|
||||
* This section must be kept in sync with the actual Actor trait.
|
||||
*
|
||||
* BOYSCOUT RULE: whenever you read this, verify that!
|
||||
*/
|
||||
//#lifecycle-callbacks
|
||||
public void preStart() {
|
||||
}
|
||||
|
||||
public void preRestart(Throwable reason, Optional<Object> message) {
|
||||
for (ActorRef each : getContext().getChildren()) {
|
||||
getContext().unwatch(each);
|
||||
getContext().stop(each);
|
||||
}
|
||||
postStop();
|
||||
}
|
||||
|
||||
public void postRestart(Throwable reason) {
|
||||
preStart();
|
||||
}
|
||||
|
||||
public void postStop() {
|
||||
}
|
||||
//#lifecycle-callbacks
|
||||
|
||||
}
|
||||
|
||||
public static class Hook extends AbstractActor {
|
||||
ActorRef target = null;
|
||||
public Hook() {
|
||||
receive(emptyBehavior());
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
|
||||
//#preStart
|
||||
@Override
|
||||
public void preStart() {
|
||||
target = context().actorOf(Props.create(MyActor.class, "target"));
|
||||
target = getContext().actorOf(Props.create(MyActor.class, "target"));
|
||||
}
|
||||
//#preStart
|
||||
//#postStop
|
||||
|
|
@ -207,7 +329,7 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
//#tell
|
||||
final Object result = "";
|
||||
//#forward
|
||||
target.forward(result, context());
|
||||
target.forward(result, getContext());
|
||||
//#forward
|
||||
target = null;
|
||||
//#clean-up-some-resources
|
||||
|
|
@ -218,28 +340,30 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
public void compileSelections() {
|
||||
//#selection-local
|
||||
// will look up this absolute path
|
||||
context().actorSelection("/user/serviceA/actor");
|
||||
getContext().actorSelection("/user/serviceA/actor");
|
||||
// will look up sibling beneath same supervisor
|
||||
context().actorSelection("../joe");
|
||||
getContext().actorSelection("../joe");
|
||||
//#selection-local
|
||||
|
||||
//#selection-wildcard
|
||||
// will look all children to serviceB with names starting with worker
|
||||
context().actorSelection("/user/serviceB/worker*");
|
||||
getContext().actorSelection("/user/serviceB/worker*");
|
||||
// will look up all siblings beneath same supervisor
|
||||
context().actorSelection("../*");
|
||||
getContext().actorSelection("../*");
|
||||
//#selection-wildcard
|
||||
|
||||
//#selection-remote
|
||||
context().actorSelection("akka.tcp://app@otherhost:1234/user/serviceB");
|
||||
getContext().actorSelection("akka.tcp://app@otherhost:1234/user/serviceB");
|
||||
//#selection-remote
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReplyException extends AbstractActor {
|
||||
public ReplyException() {
|
||||
receive(ReceiveBuilder.
|
||||
matchAny(x -> {
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(x -> {
|
||||
//#reply-exception
|
||||
try {
|
||||
String result = operation();
|
||||
|
|
@ -249,8 +373,8 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
throw e;
|
||||
}
|
||||
//#reply-exception
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private String operation() {
|
||||
|
|
@ -267,28 +391,31 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
public static final Shutdown SHUTDOWN = Shutdown.Shutdown;
|
||||
|
||||
private ActorRef worker =
|
||||
context().watch(context().actorOf(Props.create(Cruncher.class), "worker"));
|
||||
getContext().watch(getContext().actorOf(Props.create(Cruncher.class), "worker"));
|
||||
|
||||
public Manager() {
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("job", s -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("job", s -> {
|
||||
worker.tell("crunch", self());
|
||||
}).
|
||||
matchEquals(SHUTDOWN, x -> {
|
||||
})
|
||||
.matchEquals(SHUTDOWN, x -> {
|
||||
worker.tell(PoisonPill.getInstance(), self());
|
||||
context().become(shuttingDown);
|
||||
}).build()
|
||||
);
|
||||
getContext().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();
|
||||
private AbstractActor.Receive shuttingDown() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("job", s ->
|
||||
sender().tell("service unavailable, shutting down", self())
|
||||
)
|
||||
.match(Terminated.class, t -> t.actor().equals(worker), t ->
|
||||
getContext().stop(self())
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#gracefulStop-actor
|
||||
|
||||
|
|
@ -309,27 +436,26 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
|
||||
|
||||
public static class Cruncher extends AbstractActor {
|
||||
public Cruncher() {
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("crunch", s -> { }).build()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().matchEquals("crunch", s -> { }).build();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#swapper
|
||||
public class Swapper extends AbstractLoggingActor {
|
||||
public Swapper() {
|
||||
receive(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()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals(Swap, s -> {
|
||||
log().info("Hi");
|
||||
getContext().become(receiveBuilder().
|
||||
matchEquals(Swap, x -> {
|
||||
log().info("Ho");
|
||||
getContext().unbecome(); // resets the latest 'become' (just for fun)
|
||||
}).build(), false); // push on top instead of replace
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,29 +544,32 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
//#receive-timeout
|
||||
public class ReceiveTimeoutActor extends AbstractActor {
|
||||
//#receive-timeout
|
||||
ActorRef target = context().system().deadLetters();
|
||||
ActorRef target = getContext().system().deadLetters();
|
||||
//#receive-timeout
|
||||
public ReceiveTimeoutActor() {
|
||||
// To set an initial delay
|
||||
context().setReceiveTimeout(Duration.create("10 seconds"));
|
||||
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("Hello", s -> {
|
||||
getContext().setReceiveTimeout(Duration.create(10, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("Hello", s -> {
|
||||
// To set in a response to a message
|
||||
context().setReceiveTimeout(Duration.create("1 second"));
|
||||
getContext().setReceiveTimeout(Duration.create(1, TimeUnit.SECONDS));
|
||||
//#receive-timeout
|
||||
target = sender();
|
||||
target.tell("Hello world", self());
|
||||
//#receive-timeout
|
||||
}).
|
||||
match(ReceiveTimeout.class, r -> {
|
||||
})
|
||||
.match(ReceiveTimeout.class, r -> {
|
||||
// To turn it off
|
||||
context().setReceiveTimeout(Duration.Undefined());
|
||||
getContext().setReceiveTimeout(Duration.Undefined());
|
||||
//#receive-timeout
|
||||
target.tell("timeout", self());
|
||||
//#receive-timeout
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#receive-timeout
|
||||
|
|
@ -460,35 +589,40 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
static
|
||||
//#hot-swap-actor
|
||||
public class HotSwapActor extends AbstractActor {
|
||||
private PartialFunction<Object, BoxedUnit> angry;
|
||||
private PartialFunction<Object, BoxedUnit> happy;
|
||||
private AbstractActor.Receive angry;
|
||||
private AbstractActor.Receive happy;
|
||||
|
||||
public HotSwapActor() {
|
||||
angry =
|
||||
ReceiveBuilder.
|
||||
matchEquals("foo", s -> {
|
||||
receiveBuilder()
|
||||
.matchEquals("foo", s -> {
|
||||
sender().tell("I am already angry?", self());
|
||||
}).
|
||||
matchEquals("bar", s -> {
|
||||
context().become(happy);
|
||||
}).build();
|
||||
})
|
||||
.matchEquals("bar", s -> {
|
||||
getContext().become(happy);
|
||||
})
|
||||
.build();
|
||||
|
||||
happy = ReceiveBuilder.
|
||||
matchEquals("bar", s -> {
|
||||
happy = receiveBuilder()
|
||||
.matchEquals("bar", s -> {
|
||||
sender().tell("I am already happy :-)", self());
|
||||
}).
|
||||
matchEquals("foo", s -> {
|
||||
context().become(angry);
|
||||
}).build();
|
||||
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("foo", s -> {
|
||||
context().become(angry);
|
||||
}).
|
||||
matchEquals("bar", s -> {
|
||||
context().become(happy);
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.matchEquals("foo", s -> {
|
||||
getContext().become(angry);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("foo", s ->
|
||||
getContext().become(angry)
|
||||
)
|
||||
.matchEquals("bar", s ->
|
||||
getContext().become(happy)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#hot-swap-actor
|
||||
|
|
@ -516,19 +650,21 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
static
|
||||
//#stash
|
||||
public class ActorWithProtocol extends AbstractActorWithStash {
|
||||
public ActorWithProtocol() {
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("open", s -> {
|
||||
context().become(ReceiveBuilder.
|
||||
matchEquals("write", ws -> { /* do writing */ }).
|
||||
matchEquals("close", cs -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("open", s -> {
|
||||
getContext().become(receiveBuilder()
|
||||
.matchEquals("write", ws -> { /* do writing */ })
|
||||
.matchEquals("close", cs -> {
|
||||
unstashAll();
|
||||
context().unbecome();
|
||||
}).
|
||||
matchAny(msg -> stash()).build(), false);
|
||||
}).
|
||||
matchAny(msg -> stash()).build()
|
||||
);
|
||||
getContext().unbecome();
|
||||
})
|
||||
.matchAny(msg -> stash())
|
||||
.build(), false);
|
||||
})
|
||||
.matchAny(msg -> stash())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#stash
|
||||
|
|
@ -541,21 +677,24 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
static
|
||||
//#watch
|
||||
public class WatchActor extends AbstractActor {
|
||||
private final ActorRef child = context().actorOf(Props.empty(), "target");
|
||||
private final ActorRef child = getContext().actorOf(Props.empty(), "target");
|
||||
private ActorRef lastSender = system.deadLetters();
|
||||
|
||||
public WatchActor() {
|
||||
context().watch(child); // <-- this is the only call needed for registration
|
||||
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("kill", s -> {
|
||||
context().stop(child);
|
||||
getContext().watch(child); // <-- this is the only call needed for registration
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("kill", s -> {
|
||||
getContext().stop(child);
|
||||
lastSender = sender();
|
||||
}).
|
||||
match(Terminated.class, t -> t.actor().equals(child), t -> {
|
||||
})
|
||||
.match(Terminated.class, t -> t.actor().equals(child), t -> {
|
||||
lastSender.tell("finished", self());
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#watch
|
||||
|
|
@ -578,26 +717,30 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
final Integer identifyId = 1;
|
||||
|
||||
public Follower(){
|
||||
ActorSelection selection = context().actorSelection("/user/another");
|
||||
ActorSelection selection = getContext().actorSelection("/user/another");
|
||||
selection.tell(new Identify(identifyId), self());
|
||||
|
||||
receive(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();
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(ActorIdentity.class, id -> id.getActorRef().isPresent(), id -> {
|
||||
ActorRef ref = id.getActorRef().get();
|
||||
getContext().watch(ref);
|
||||
getContext().become(active(ref));
|
||||
})
|
||||
.match(ActorIdentity.class, id -> !id.getActorRef().isPresent(), id -> {
|
||||
getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
final AbstractActor.Receive active(final ActorRef another) {
|
||||
return receiveBuilder()
|
||||
.match(Terminated.class, t -> t.actor().equals(another), t ->
|
||||
getContext().stop(self())
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#identify
|
||||
|
|
@ -615,73 +758,70 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class NoReceiveActor extends AbstractActor {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void noReceiveActor() {
|
||||
EventFilter ex1 = new ErrorFilter(ActorInitializationException.class);
|
||||
EventFilter[] ignoreExceptions = { ex1 };
|
||||
try {
|
||||
system.eventStream().publish(new TestEvent.Mute(immutableSeq(ignoreExceptions)));
|
||||
new JavaTestKit(system) {{
|
||||
final ActorRef victim = new EventFilter<ActorRef>(ActorInitializationException.class) {
|
||||
protected ActorRef run() {
|
||||
return system.actorOf(Props.create(NoReceiveActor.class), "victim");
|
||||
}
|
||||
}.message("Actor behavior has not been set with receive(...)").occurrences(1).exec();
|
||||
public void usePatternsAskPipe() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
ActorRef actorA = system.actorOf(TestActors.echoActorProps());
|
||||
ActorRef actorB = system.actorOf(TestActors.echoActorProps());
|
||||
ActorRef actorC = getRef();
|
||||
|
||||
assertEquals(true, victim.isTerminated());
|
||||
}};
|
||||
} finally {
|
||||
system.eventStream().publish(new TestEvent.UnMute(immutableSeq(ignoreExceptions)));
|
||||
}
|
||||
//#ask-pipe
|
||||
final Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
|
||||
|
||||
final ArrayList<Future<Object>> futures = new ArrayList<Future<Object>>();
|
||||
futures.add(ask(actorA, "request", 1000)); // using 1000ms timeout
|
||||
futures.add(ask(actorB, "another request", t)); // using timeout from
|
||||
// above
|
||||
|
||||
final Future<Iterable<Object>> aggregate = Futures.sequence(futures,
|
||||
system.dispatcher());
|
||||
|
||||
final Future<Result> transformed = aggregate.map(
|
||||
new Mapper<Iterable<Object>, Result>() {
|
||||
public Result apply(Iterable<Object> coll) {
|
||||
final Iterator<Object> it = coll.iterator();
|
||||
final String x = (String) it.next();
|
||||
final String s = (String) it.next();
|
||||
return new Result(x, s);
|
||||
}
|
||||
}, system.dispatcher());
|
||||
|
||||
pipe(transformed, system.dispatcher()).to(actorC);
|
||||
//#ask-pipe
|
||||
|
||||
expectMsgEquals(new Result("request", "another request"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class MultipleReceiveActor extends AbstractActor {
|
||||
public MultipleReceiveActor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, s1 -> s1.toLowerCase().equals("become"), s1 -> {
|
||||
sender().tell(s1.toUpperCase(), self());
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, s2 -> {
|
||||
sender().tell(s2.toLowerCase(), self());
|
||||
}).build()
|
||||
);
|
||||
}).
|
||||
match(String.class, s1 -> {
|
||||
sender().tell(s1.toUpperCase(), self());
|
||||
}).build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void multipleReceiveActor() {
|
||||
EventFilter ex1 = new ErrorFilter(IllegalActorStateException.class);
|
||||
EventFilter[] ignoreExceptions = { ex1 };
|
||||
try {
|
||||
system.eventStream().publish(new TestEvent.Mute(immutableSeq(ignoreExceptions)));
|
||||
new JavaTestKit(system) {{
|
||||
new EventFilter<Boolean>(IllegalActorStateException.class) {
|
||||
protected Boolean run() {
|
||||
ActorRef victim = system.actorOf(Props.create(MultipleReceiveActor.class), "victim2");
|
||||
victim.tell("Foo", getRef());
|
||||
expectMsgEquals("FOO");
|
||||
victim.tell("bEcoMe", getRef());
|
||||
expectMsgEquals("BECOME");
|
||||
victim.tell("Foo", getRef());
|
||||
// if it's upper case, then the actor was restarted
|
||||
expectMsgEquals("FOO");
|
||||
return true;
|
||||
}
|
||||
}.message("Actor behavior has already been set with receive(...), " +
|
||||
"use context().become(...) to change it later").occurrences(1).exec();
|
||||
}};
|
||||
} finally {
|
||||
system.eventStream().publish(new TestEvent.UnMute(immutableSeq(ignoreExceptions)));
|
||||
}
|
||||
public void useKill() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
ActorRef victim = system.actorOf(TestActors.echoActorProps());
|
||||
watch(victim);
|
||||
//#kill
|
||||
victim.tell(akka.actor.Kill.getInstance(), ActorRef.noSender());
|
||||
//#kill
|
||||
expectTerminated(Duration.create(3, TimeUnit.SECONDS), victim);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usePoisonPill() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
ActorRef victim = system.actorOf(TestActors.echoActorProps());
|
||||
watch(victim);
|
||||
//#poison-pill
|
||||
victim.tell(akka.actor.PoisonPill.getInstance(), ActorRef.noSender());
|
||||
//#poison-pill
|
||||
expectTerminated(Duration.create(3, TimeUnit.SECONDS), victim);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -691,7 +831,7 @@ public class ActorDocTest extends AbstractJavaTest {
|
|||
CoordinatedShutdown.get(system).addTask(
|
||||
CoordinatedShutdown.PhaseBeforeServiceUnbind(), "someTaskName",
|
||||
() -> {
|
||||
return ask(someActor, "stop", new Timeout(5, TimeUnit.SECONDS))
|
||||
return akka.pattern.PatternsCS.ask(someActor, "stop", new Timeout(5, TimeUnit.SECONDS))
|
||||
.thenApply(reply -> Done.getInstance());
|
||||
});
|
||||
//#coordinated-shutdown-addTask
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actorlambda;
|
||||
|
||||
import docs.AbstractJavaTest;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.Await;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.JavaTestKit;
|
||||
|
||||
//#import
|
||||
import akka.actor.Actor;
|
||||
import akka.actor.IndirectActorProducer;
|
||||
//#import
|
||||
|
||||
public class DependencyInjectionDocTest extends AbstractJavaTest {
|
||||
|
||||
public static class TheActor extends AbstractActor {
|
||||
|
||||
final String s;
|
||||
|
||||
public TheActor(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, msg -> {
|
||||
sender().tell(s, self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
system = ActorSystem.create("DependencyInjectionDocTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
Await.ready(system.terminate(), Duration.create("5 seconds"));
|
||||
}
|
||||
|
||||
//this is just to make the test below a tiny fraction nicer
|
||||
private ActorSystem getContext() {
|
||||
return system;
|
||||
}
|
||||
|
||||
static
|
||||
//#creating-indirectly
|
||||
class DependencyInjector implements IndirectActorProducer {
|
||||
final Object applicationContext;
|
||||
final String beanName;
|
||||
|
||||
public DependencyInjector(Object applicationContext, String beanName) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Actor> actorClass() {
|
||||
return TheActor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TheActor produce() {
|
||||
TheActor result;
|
||||
//#obtain-fresh-Actor-instance-from-DI-framework
|
||||
result = new TheActor((String) applicationContext);
|
||||
//#obtain-fresh-Actor-instance-from-DI-framework
|
||||
return result;
|
||||
}
|
||||
}
|
||||
//#creating-indirectly
|
||||
|
||||
@Test
|
||||
public void indirectActorOf() {
|
||||
final String applicationContext = "...";
|
||||
//#creating-indirectly
|
||||
|
||||
final ActorRef myActor = getContext().actorOf(
|
||||
Props.create(DependencyInjector.class, applicationContext, "TheActor"),
|
||||
"TheActor");
|
||||
//#creating-indirectly
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
myActor.tell("hello", getRef());
|
||||
expectMsgEquals("...");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,37 +3,41 @@
|
|||
*/
|
||||
package docs.actorlambda;
|
||||
|
||||
//#testkit
|
||||
import akka.actor.*;
|
||||
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import docs.AbstractJavaTest;
|
||||
import java.util.Optional;
|
||||
|
||||
import static akka.pattern.Patterns.ask;
|
||||
|
||||
//#testkit
|
||||
import akka.testkit.JavaTestKit;
|
||||
import akka.testkit.TestProbe;
|
||||
import akka.testkit.ErrorFilter;
|
||||
import akka.testkit.EventFilter;
|
||||
import akka.testkit.TestEvent;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static akka.japi.Util.immutableSeq;
|
||||
import scala.concurrent.Await;
|
||||
|
||||
//#testkit
|
||||
|
||||
//#supervisor
|
||||
import akka.japi.pf.DeciderBuilder;
|
||||
import static akka.actor.SupervisorStrategy.resume;
|
||||
import static akka.actor.SupervisorStrategy.restart;
|
||||
import static akka.actor.SupervisorStrategy.stop;
|
||||
import static akka.actor.SupervisorStrategy.escalate;
|
||||
import akka.japi.pf.DeciderBuilder;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import docs.AbstractJavaTest;
|
||||
import scala.PartialFunction;
|
||||
import scala.concurrent.Await;
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import akka.testkit.TestProbe;
|
||||
|
||||
//#testkit
|
||||
import akka.testkit.ErrorFilter;
|
||||
import akka.testkit.EventFilter;
|
||||
import akka.testkit.TestEvent;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static akka.japi.Util.immutableSeq;
|
||||
import scala.Option;
|
||||
//#supervisor
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.AfterClass;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
//#testkit
|
||||
public class FaultHandlingTest extends AbstractJavaTest {
|
||||
|
|
@ -65,12 +69,13 @@ public class FaultHandlingTest extends AbstractJavaTest {
|
|||
|
||||
//#strategy
|
||||
|
||||
public Supervisor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Props.class, props -> {
|
||||
sender().tell(context().actorOf(props), self());
|
||||
}).build()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Props.class, props -> {
|
||||
sender().tell(getContext().actorOf(props), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,16 +100,17 @@ public class FaultHandlingTest extends AbstractJavaTest {
|
|||
|
||||
//#strategy2
|
||||
|
||||
public Supervisor2() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Props.class, props -> {
|
||||
sender().tell(context().actorOf(props), self());
|
||||
}).build()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Props.class, props -> {
|
||||
sender().tell(getContext().actorOf(props), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRestart(Throwable cause, Option<Object> msg) {
|
||||
public void preRestart(Throwable cause, Optional<Object> msg) {
|
||||
// do not kill all children, which is the default here
|
||||
}
|
||||
}
|
||||
|
|
@ -116,12 +122,13 @@ public class FaultHandlingTest extends AbstractJavaTest {
|
|||
public class Child extends AbstractActor {
|
||||
int state = 0;
|
||||
|
||||
public Child() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Exception.class, exception -> { throw exception; }).
|
||||
match(Integer.class, i -> state = i).
|
||||
matchEquals("get", s -> sender().tell(state, self())).build()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Exception.class, exception -> { throw exception; })
|
||||
.match(Integer.class, i -> state = i)
|
||||
.matchEquals("get", s -> sender().tell(state, self()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ import akka.japi.pf.UnitPFBuilder;
|
|||
|
||||
//#actor
|
||||
public class GraduallyBuiltActor extends AbstractActor {
|
||||
private final LoggingAdapter log = Logging.getLogger(context().system(), this);
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
public GraduallyBuiltActor() {
|
||||
UnitPFBuilder<Object> builder = ReceiveBuilder.create();
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder builder = ReceiveBuilder.create();
|
||||
|
||||
builder.match(String.class, s -> {
|
||||
log.info("Received String message: {}", s);
|
||||
//#actor
|
||||
|
|
@ -27,9 +29,12 @@ public class GraduallyBuiltActor extends AbstractActor {
|
|||
//#reply
|
||||
//#actor
|
||||
});
|
||||
|
||||
// do some other stuff in between
|
||||
|
||||
builder.matchAny(o -> log.info("received unknown message"));
|
||||
receive(builder.build());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
//#actor
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import akka.actor.ActorRef;
|
|||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.japi.pf.FI;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import docs.AbstractJavaTest;
|
||||
import org.junit.AfterClass;
|
||||
|
|
@ -16,7 +15,7 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
import scala.concurrent.Await;
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InitializationDocTest extends AbstractJavaTest {
|
||||
|
|
@ -32,24 +31,57 @@ public class InitializationDocTest extends AbstractJavaTest {
|
|||
public static void afterClass() throws Exception {
|
||||
Await.ready(system.terminate(), Duration.create("5 seconds"));
|
||||
}
|
||||
|
||||
static public class PreStartInitExample extends AbstractActor {
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
|
||||
//#preStartInit
|
||||
@Override
|
||||
public void preStart() {
|
||||
// Initialize children here
|
||||
}
|
||||
|
||||
// Overriding postRestart to disable the call to preStart()
|
||||
// after restarts
|
||||
@Override
|
||||
public void postRestart(Throwable reason) {
|
||||
}
|
||||
|
||||
// The default implementation of preRestart() stops all the children
|
||||
// of the actor. To opt-out from stopping the children, we
|
||||
// have to override preRestart()
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Optional<Object> message)
|
||||
throws Exception {
|
||||
// Keep the call to postStop(), but no stopping of children
|
||||
postStop();
|
||||
}
|
||||
//#preStartInit
|
||||
|
||||
}
|
||||
|
||||
public static class MessageInitExample extends AbstractActor {
|
||||
private String initializeMe = null;
|
||||
|
||||
public MessageInitExample() {
|
||||
//#messageInit
|
||||
receive(ReceiveBuilder.
|
||||
matchEquals("init", m1 -> {
|
||||
initializeMe = "Up and running";
|
||||
context().become(ReceiveBuilder.
|
||||
matchEquals("U OK?", m2 -> {
|
||||
sender().tell(initializeMe, self());
|
||||
}).build());
|
||||
|
||||
}).build()
|
||||
//#messageInit
|
||||
);
|
||||
//#messageInit
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("init", m1 -> {
|
||||
initializeMe = "Up and running";
|
||||
getContext().become(receiveBuilder()
|
||||
.matchEquals("U OK?", m2 -> {
|
||||
sender().tell(initializeMe, self());
|
||||
})
|
||||
.build());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#messageInit
|
||||
}
|
||||
|
||||
public class GenericMessage<T> {
|
||||
|
|
@ -61,24 +93,27 @@ public class InitializationDocTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
public static class GenericActor extends AbstractActor {
|
||||
public GenericActor() {
|
||||
receive(ReceiveBuilder.match(GenericMessage.class, (GenericMessage<String> msg) -> {
|
||||
GenericMessage<String> message = msg;
|
||||
sender().tell(message.value.toUpperCase(), self());
|
||||
|
||||
}).build());
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchUnchecked(GenericMessage.class, (GenericMessage<String> msg) -> {
|
||||
GenericMessage<String> message = msg;
|
||||
sender().tell(message.value.toUpperCase(), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
static class GenericActorWithPredicate extends AbstractActor {
|
||||
public GenericActorWithPredicate() {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
FI.TypedPredicate<GenericMessage<String>> typedPredicate = s -> !s.value.isEmpty();
|
||||
|
||||
receive(ReceiveBuilder.match(GenericMessage.class, typedPredicate, (GenericMessage<String> msg) -> {
|
||||
sender().tell(msg.value.toUpperCase(), self());
|
||||
}).build());
|
||||
return receiveBuilder()
|
||||
.matchUnchecked(GenericMessage.class, typedPredicate, (GenericMessage<String> msg) -> {
|
||||
sender().tell(msg.value.toUpperCase(), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,26 +8,26 @@ package docs.actorlambda;
|
|||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
|
||||
//#imports
|
||||
|
||||
//#my-actor
|
||||
public class MyActor extends AbstractActor {
|
||||
private final LoggingAdapter log = Logging.getLogger(context().system(), this);
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
public MyActor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, s -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
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()
|
||||
);
|
||||
})
|
||||
.matchAny(o -> log.info("received unknown message"))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#my-actor
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
package docs.actorlambda;
|
||||
|
||||
//#my-bounded-untyped-actor
|
||||
import akka.dispatch.BoundedMessageQueueSemantics;
|
||||
import akka.dispatch.RequiresMessageQueue;
|
||||
|
||||
public class MyBoundedUntypedActor extends MyUntypedActor
|
||||
public class MyBoundedActor extends MyActor
|
||||
implements RequiresMessageQueue<BoundedMessageQueueSemantics> {
|
||||
}
|
||||
//#my-bounded-untyped-actor
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.actorlambda;
|
||||
|
||||
//#my-stopping-actor
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
public class MyStoppingActor extends AbstractActor {
|
||||
|
||||
ActorRef child = null;
|
||||
|
||||
// ... creation of child ...
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("interrupt-child", m ->
|
||||
getContext().stop(child)
|
||||
)
|
||||
.matchEquals("done", m ->
|
||||
getContext().stop(self())
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#my-stopping-actor
|
||||
|
||||
|
|
@ -7,30 +7,30 @@ package docs.actorlambda;
|
|||
//#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 -> {
|
||||
private Receive guarded = receiveBuilder()
|
||||
.match(String.class, s -> s.contains("guard"), s -> {
|
||||
sender().tell("contains(guard): " + s, self());
|
||||
context().unbecome();
|
||||
}).build();
|
||||
getContext().unbecome();
|
||||
})
|
||||
.build();
|
||||
|
||||
public SampleActor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Double.class, d -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Double.class, d -> {
|
||||
sender().tell(d.isNaN() ? 0 : d, self());
|
||||
}).
|
||||
match(Integer.class, i -> {
|
||||
})
|
||||
.match(Integer.class, i -> {
|
||||
sender().tell(i * 10, self());
|
||||
}).
|
||||
match(String.class, s -> s.startsWith("guard"), s -> {
|
||||
})
|
||||
.match(String.class, s -> s.startsWith("guard"), s -> {
|
||||
sender().tell("startsWith(guard): " + s.toUpperCase(), self());
|
||||
context().become(guarded, false);
|
||||
}).build()
|
||||
);
|
||||
getContext().become(guarded, false);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#sample-actor
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ public class FSMDocTest extends AbstractJavaTest {
|
|||
expectMsgEquals(Active);
|
||||
expectMsgEquals(Data.Foo);
|
||||
String msg = expectMsgClass(String.class);
|
||||
assertTrue(msg.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
||||
assertThat(msg, CoreMatchers.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,24 +67,24 @@ public class FaultHandlingDocSample {
|
|||
public void preStart() {
|
||||
// If we don't get any progress within 15 seconds then the service
|
||||
// is unavailable
|
||||
context().setReceiveTimeout(Duration.create("15 seconds"));
|
||||
getContext().setReceiveTimeout(Duration.create("15 seconds"));
|
||||
}
|
||||
|
||||
public Listener() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(Progress.class, progress -> {
|
||||
log().info("Current progress: {} %", progress.percent);
|
||||
if (progress.percent >= 100.0) {
|
||||
log().info("That's all, shutting down");
|
||||
context().system().terminate();
|
||||
getContext().system().terminate();
|
||||
}
|
||||
}).
|
||||
matchEquals(ReceiveTimeout.getInstance(), x -> {
|
||||
// No progress within 15 seconds, ServiceUnavailable
|
||||
log().error("Shutting down due to unavailable service");
|
||||
context().system().terminate();
|
||||
}).build(), context()
|
||||
));
|
||||
getContext().system().terminate();
|
||||
}).build(), getContext());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ public class FaultHandlingDocSample {
|
|||
// The sender of the initial Start message will continuously be notified
|
||||
// about progress
|
||||
ActorRef progressListener;
|
||||
final ActorRef counterService = context().actorOf(
|
||||
final ActorRef counterService = getContext().actorOf(
|
||||
Props.create(CounterService.class), "counter");
|
||||
final int totalCount = 51;
|
||||
|
||||
|
|
@ -134,13 +134,14 @@ public class FaultHandlingDocSample {
|
|||
return strategy;
|
||||
}
|
||||
|
||||
public Worker() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
matchEquals(Start, x -> progressListener == null, x -> {
|
||||
progressListener = sender();
|
||||
context().system().scheduler().schedule(
|
||||
getContext().system().scheduler().schedule(
|
||||
Duration.Zero(), Duration.create(1, "second"), self(), Do,
|
||||
context().dispatcher(), null
|
||||
getContext().dispatcher(), null
|
||||
);
|
||||
}).
|
||||
matchEquals(Do, x -> {
|
||||
|
|
@ -154,10 +155,9 @@ public class FaultHandlingDocSample {
|
|||
public Progress apply(CurrentCount c) {
|
||||
return new Progress(100.0 * c.count / totalCount);
|
||||
}
|
||||
}, context().dispatcher()), context().dispatcher())
|
||||
}, getContext().dispatcher()), getContext().dispatcher())
|
||||
.to(progressListener);
|
||||
}).build(), context())
|
||||
);
|
||||
}).build(), getContext());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ public class FaultHandlingDocSample {
|
|||
* when it has been terminated.
|
||||
*/
|
||||
void initStorage() {
|
||||
storage = context().watch(context().actorOf(
|
||||
storage = getContext().watch(getContext().actorOf(
|
||||
Props.create(Storage.class), "storage"));
|
||||
// Tell the counter, if any, to use the new storage
|
||||
if (counter != null)
|
||||
|
|
@ -263,12 +263,13 @@ public class FaultHandlingDocSample {
|
|||
storage.tell(new Get(key), self());
|
||||
}
|
||||
|
||||
public CounterService() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(Entry.class, entry -> entry.key.equals(key) && counter == null, entry -> {
|
||||
// Reply from Storage of the initial value, now we can create the Counter
|
||||
final long value = entry.value;
|
||||
counter = context().actorOf(Props.create(Counter.class, key, value));
|
||||
counter = getContext().actorOf(Props.create(Counter.class, key, value));
|
||||
// Tell the counter to use current storage
|
||||
counter.tell(new UseStorage(storage), self());
|
||||
// and send the buffered backlog to the counter
|
||||
|
|
@ -290,15 +291,14 @@ public class FaultHandlingDocSample {
|
|||
// Tell the counter that there is no storage for the moment
|
||||
counter.tell(new UseStorage(null), self());
|
||||
// Try to re-establish storage after while
|
||||
context().system().scheduler().scheduleOnce(
|
||||
getContext().system().scheduler().scheduleOnce(
|
||||
Duration.create(10, "seconds"), self(), Reconnect,
|
||||
context().dispatcher(), null);
|
||||
getContext().dispatcher(), null);
|
||||
}).
|
||||
matchEquals(Reconnect, o -> {
|
||||
// Re-establish storage after the scheduled delay
|
||||
initStorage();
|
||||
}).build(), context())
|
||||
);
|
||||
}).build(), getContext());
|
||||
}
|
||||
|
||||
void forwardOrPlaceInBacklog(Object msg) {
|
||||
|
|
@ -311,7 +311,7 @@ public class FaultHandlingDocSample {
|
|||
" lack of initial value");
|
||||
backlog.add(new SenderMsgPair(sender(), msg));
|
||||
} else {
|
||||
counter.forward(msg, context());
|
||||
counter.forward(msg, getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -345,8 +345,11 @@ public class FaultHandlingDocSample {
|
|||
public Counter(String key, long initialValue) {
|
||||
this.key = key;
|
||||
this.count = initialValue;
|
||||
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(UseStorage.class, useStorage -> {
|
||||
storage = useStorage.storage;
|
||||
storeCount();
|
||||
|
|
@ -357,8 +360,7 @@ public class FaultHandlingDocSample {
|
|||
}).
|
||||
matchEquals(GetCurrentCount, gcc -> {
|
||||
sender().tell(new CurrentCount(key, count), self());
|
||||
}).build(), context())
|
||||
);
|
||||
}).build(), getContext());
|
||||
}
|
||||
|
||||
void storeCount() {
|
||||
|
|
@ -430,8 +432,9 @@ public class FaultHandlingDocSample {
|
|||
|
||||
final DummyDB db = DummyDB.instance;
|
||||
|
||||
public Storage() {
|
||||
receive(LoggingReceive.create(ReceiveBuilder.
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return LoggingReceive.create(receiveBuilder().
|
||||
match(Store.class, store -> {
|
||||
db.save(store.entry.key, store.entry.value);
|
||||
}).
|
||||
|
|
@ -439,8 +442,7 @@ public class FaultHandlingDocSample {
|
|||
Long value = db.load(get.key);
|
||||
sender().tell(new Entry(get.key, value == null ?
|
||||
Long.valueOf(0L) : value), self());
|
||||
}).build(), context())
|
||||
);
|
||||
}).build(), getContext());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public class Consumer2 extends UntypedConsumerActor {
|
|||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
String body = camelMessage.getBodyAs(String.class, getCamelContext());
|
||||
getSender().tell(String.format("Received message: %s",body), getSelf());
|
||||
sender().tell(String.format("Received message: %s",body), self());
|
||||
} else
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ public class Consumer3 extends UntypedConsumerActor{
|
|||
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof CamelMessage) {
|
||||
getSender().tell(Ack.getInstance(), getSelf());
|
||||
sender().tell(Ack.getInstance(), self());
|
||||
// on success
|
||||
// ..
|
||||
Exception someException = new Exception("e1");
|
||||
// on failure
|
||||
getSender().tell(new Status.Failure(someException), getSelf());
|
||||
sender().tell(new Status.Failure(someException), self());
|
||||
} else
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class Consumer4 extends UntypedConsumerActor {
|
|||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
String body = camelMessage.getBodyAs(String.class, getCamelContext());
|
||||
getSender().tell(String.format("Hello %s",body), getSelf());
|
||||
sender().tell(String.format("Hello %s",body), self());
|
||||
} else
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public class ErrorThrowingConsumer extends UntypedConsumerActor{
|
|||
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Option<Object> message) {
|
||||
getSender().tell(new Status.Failure(reason), getSelf());
|
||||
sender().tell(new Status.Failure(reason), self());
|
||||
}
|
||||
}
|
||||
//#ErrorThrowingConsumer
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package docs.camel;
|
||||
//#ProducerTemplate
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.UntypedAbstractActor;
|
||||
import akka.camel.Camel;
|
||||
import akka.camel.CamelExtension;
|
||||
import org.apache.camel.ProducerTemplate;
|
||||
|
||||
public class MyActor extends UntypedActor {
|
||||
public class MyActor extends UntypedAbstractActor {
|
||||
public void onReceive(Object message) {
|
||||
Camel camel = CamelExtension.get(getContext().system());
|
||||
ProducerTemplate template = camel.template();
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
package docs.camel;
|
||||
//#RequestProducerTemplate
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.camel.Camel;
|
||||
import akka.camel.CamelExtension;
|
||||
import org.apache.camel.ProducerTemplate;
|
||||
|
||||
public class RequestBodyActor extends UntypedActor {
|
||||
public void onReceive(Object message) {
|
||||
Camel camel = CamelExtension.get(getContext().system());
|
||||
ProducerTemplate template = camel.template();
|
||||
getSender().tell(template.requestBody("direct:news", message), getSelf());
|
||||
public class RequestBodyActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(message -> {
|
||||
Camel camel = CamelExtension.get(getContext().system());
|
||||
ProducerTemplate template = camel.template();
|
||||
sender().tell(template.requestBody("direct:news", message), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#RequestProducerTemplate
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
package docs.camel;
|
||||
//#CustomRoute
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.UntypedAbstractActor;
|
||||
import akka.camel.CamelMessage;
|
||||
import akka.dispatch.Mapper;
|
||||
import akka.japi.Function;
|
||||
|
||||
public class Responder extends UntypedActor{
|
||||
public class Responder extends UntypedAbstractActor{
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof CamelMessage) {
|
||||
CamelMessage camelMessage = (CamelMessage) message;
|
||||
getSender().tell(createResponse(camelMessage), getSelf());
|
||||
sender().tell(createResponse(camelMessage), self());
|
||||
} else
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package docs.camel;
|
||||
//#RouteResponse
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.UntypedAbstractActor;
|
||||
import akka.camel.CamelMessage;
|
||||
|
||||
public class ResponseReceiver extends UntypedActor{
|
||||
public class ResponseReceiver extends UntypedAbstractActor{
|
||||
public void onReceive(Object message) {
|
||||
if(message instanceof CamelMessage) {
|
||||
// do something with the forwarded response
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ package docs.ddata;
|
|||
|
||||
//#data-bot
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import scala.concurrent.duration.Duration;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
|
|
@ -29,25 +30,26 @@ public class DataBot extends AbstractActor {
|
|||
|
||||
private static final String TICK = "tick";
|
||||
|
||||
private final LoggingAdapter log = Logging.getLogger(context().system(), this);
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
private final ActorRef replicator =
|
||||
DistributedData.get(context().system()).replicator();
|
||||
private final Cluster node = Cluster.get(context().system());
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
private final Cluster node = Cluster.get(getContext().system());
|
||||
|
||||
private final Cancellable tickTask = context().system().scheduler().schedule(
|
||||
private final Cancellable tickTask = getContext().system().scheduler().schedule(
|
||||
Duration.create(5, SECONDS), Duration.create(5, SECONDS), self(), TICK,
|
||||
context().dispatcher(), self());
|
||||
getContext().dispatcher(), self());
|
||||
|
||||
private final Key<ORSet<String>> dataKey = ORSetKey.create("key");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public DataBot() {
|
||||
receive(ReceiveBuilder
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, a -> a.equals(TICK), a -> receiveTick())
|
||||
.match(Changed.class, c -> c.key().equals(dataKey), c -> receiveChanged((Changed<ORSet<String>>) c))
|
||||
.match(UpdateResponse.class, r -> receiveUpdateResoponse())
|
||||
.build());
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,11 @@ import akka.testkit.JavaTestKit;
|
|||
import akka.testkit.TestProbe;
|
||||
import akka.serialization.SerializationExtension;
|
||||
|
||||
@SuppressWarnings({"unchecked", "unused"})
|
||||
public class DistributedDataDocTest extends AbstractJavaTest {
|
||||
|
||||
static ActorSystem system;
|
||||
|
||||
void receive(PartialFunction<Object, BoxedUnit> pf) {
|
||||
}
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
|
|
@ -55,237 +53,261 @@ public class DistributedDataDocTest extends AbstractJavaTest {
|
|||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void demonstrateUpdate() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
//#update
|
||||
final Cluster node = Cluster.get(system);
|
||||
final ActorRef replicator = DistributedData.get(system).replicator();
|
||||
static
|
||||
//#update
|
||||
class DemonstrateUpdate extends AbstractActor {
|
||||
final Cluster node = Cluster.get(getContext().system());
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
final Key<Flag> activeFlagKey = FlagKey.create("active");
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
final Key<Flag> activeFlagKey = FlagKey.create("active");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder b = receiveBuilder();
|
||||
|
||||
b.matchEquals("demonstrate update", msg -> {
|
||||
replicator.tell(new Replicator.Update<PNCounter>(counter1Key, PNCounter.create(),
|
||||
Replicator.writeLocal(), curr -> curr.increment(node, 1)), getTestActor());
|
||||
Replicator.writeLocal(), curr -> curr.increment(node, 1)), self());
|
||||
|
||||
final WriteConsistency writeTo3 = new WriteTo(3, Duration.create(1, SECONDS));
|
||||
replicator.tell(new Replicator.Update<GSet<String>>(set1Key, GSet.create(),
|
||||
writeTo3, curr -> curr.add("hello")), getTestActor());
|
||||
writeTo3, curr -> curr.add("hello")), self());
|
||||
|
||||
final WriteConsistency writeMajority =
|
||||
new WriteMajority(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Replicator.Update<ORSet<String>>(set2Key, ORSet.create(),
|
||||
writeMajority, curr -> curr.add(node, "hello")), getTestActor());
|
||||
writeMajority, curr -> curr.add(node, "hello")), self());
|
||||
|
||||
final WriteConsistency writeAll = new WriteAll(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Replicator.Update<Flag>(activeFlagKey, Flag.create(),
|
||||
writeAll, curr -> curr.switchOn()), getTestActor());
|
||||
//#update
|
||||
|
||||
expectMsgClass(UpdateSuccess.class);
|
||||
//#update-response1
|
||||
receive(ReceiveBuilder.
|
||||
match(UpdateSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
// ok
|
||||
}).build());
|
||||
//#update-response1
|
||||
|
||||
//#update-response2
|
||||
receive(ReceiveBuilder.
|
||||
match(UpdateSuccess.class, a -> a.key().equals(set1Key), a -> {
|
||||
// ok
|
||||
}).
|
||||
match(UpdateTimeout.class, a -> a.key().equals(set1Key), a -> {
|
||||
// write to 3 nodes failed within 1.second
|
||||
}).build());
|
||||
//#update-response2
|
||||
}};
|
||||
writeAll, curr -> curr.switchOn()), self());
|
||||
});
|
||||
//#update
|
||||
|
||||
//#update-response1
|
||||
b.match(UpdateSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
// ok
|
||||
});
|
||||
//#update-response1
|
||||
|
||||
//#update-response2
|
||||
b.match(UpdateSuccess.class, a -> a.key().equals(set1Key), a -> {
|
||||
// ok
|
||||
})
|
||||
.match(UpdateTimeout.class, a -> a.key().equals(set1Key), a -> {
|
||||
// write to 3 nodes failed within 1.second
|
||||
});
|
||||
//#update-response2
|
||||
|
||||
//#update
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
//#update
|
||||
|
||||
@Test
|
||||
public void demonstrateUpdateWithRequestContext() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
static
|
||||
//#update-request-context
|
||||
class DemonstrateUpdateWithRequestContext extends AbstractActor {
|
||||
final Cluster node = Cluster.get(getContext().system());
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
|
||||
//#update-request-context
|
||||
final Cluster node = Cluster.get(system);
|
||||
final ActorRef replicator = DistributedData.get(system).replicator();
|
||||
final WriteConsistency writeTwo = new WriteTo(2, Duration.create(3, SECONDS));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, a -> a.equals("increment"), a -> {
|
||||
// incoming command to increase the counter
|
||||
Optional<Object> reqContext = Optional.of(sender());
|
||||
Replicator.Update<PNCounter> upd = new Replicator.Update<PNCounter>(counter1Key,
|
||||
PNCounter.create(), writeTwo, reqContext, curr -> curr.increment(node, 1));
|
||||
replicator.tell(upd, self());
|
||||
})
|
||||
|
||||
final WriteConsistency writeTwo = new WriteTo(2, Duration.create(3, SECONDS));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
.match(UpdateSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("ack", self());
|
||||
})
|
||||
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, a -> a.equals("increment"), a -> {
|
||||
// incoming command to increase the counter
|
||||
Optional<Object> reqContext = Optional.of(getRef());
|
||||
Replicator.Update<PNCounter> upd = new Replicator.Update<PNCounter>(counter1Key,
|
||||
PNCounter.create(), writeTwo, reqContext, curr -> curr.increment(node, 1));
|
||||
replicator.tell(upd, getTestActor());
|
||||
}).
|
||||
|
||||
match(UpdateSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("ack", getTestActor());
|
||||
}).
|
||||
|
||||
match(UpdateTimeout.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("nack", getTestActor());
|
||||
}).build());
|
||||
|
||||
//#update-request-context
|
||||
.match(UpdateTimeout.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell("nack", self());
|
||||
})
|
||||
|
||||
.build();
|
||||
}
|
||||
};
|
||||
}
|
||||
//#update-request-context
|
||||
|
||||
@SuppressWarnings({ "unused", "unchecked" })
|
||||
@Test
|
||||
public void demonstrateGet() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
static
|
||||
//#get
|
||||
class DemonstrateGet extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
final Key<Flag> activeFlagKey = FlagKey.create("active");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
ReceiveBuilder b = receiveBuilder();
|
||||
|
||||
b.matchEquals("demonstrate get", msg -> {
|
||||
|
||||
//#get
|
||||
final ActorRef replicator = DistributedData.get(system).replicator();
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<GSet<String>> set1Key = GSetKey.create("set1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
final Key<Flag> activeFlagKey = FlagKey.create("active");
|
||||
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key,
|
||||
Replicator.readLocal()), getTestActor());
|
||||
|
||||
final ReadConsistency readFrom3 = new ReadFrom(3, Duration.create(1, SECONDS));
|
||||
replicator.tell(new Replicator.Get<GSet<String>>(set1Key,
|
||||
readFrom3), getTestActor());
|
||||
|
||||
final ReadConsistency readMajority = new ReadMajority(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Replicator.Get<ORSet<String>>(set2Key,
|
||||
readMajority), getTestActor());
|
||||
|
||||
final ReadConsistency readAll = new ReadAll(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Replicator.Get<Flag>(activeFlagKey,
|
||||
readAll), getTestActor());
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key,
|
||||
Replicator.readLocal()), self());
|
||||
|
||||
final ReadConsistency readFrom3 = new ReadFrom(3, Duration.create(1, SECONDS));
|
||||
replicator.tell(new Replicator.Get<GSet<String>>(set1Key,
|
||||
readFrom3), self());
|
||||
|
||||
final ReadConsistency readMajority = new ReadMajority(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Replicator.Get<ORSet<String>>(set2Key,
|
||||
readMajority), self());
|
||||
|
||||
final ReadConsistency readAll = new ReadAll(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Replicator.Get<Flag>(activeFlagKey,
|
||||
readAll), self());
|
||||
|
||||
});
|
||||
//#get
|
||||
|
||||
//#get-response1
|
||||
receive(ReceiveBuilder.
|
||||
match(GetSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
GetSuccess<PNCounter> g = a;
|
||||
BigInteger value = g.dataValue().getValue();
|
||||
}).
|
||||
match(NotFound.class, a -> a.key().equals(counter1Key), a -> {
|
||||
// key counter1 does not exist
|
||||
}).build());
|
||||
b.match(GetSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
GetSuccess<PNCounter> g = a;
|
||||
BigInteger value = g.dataValue().getValue();
|
||||
}).
|
||||
match(NotFound.class, a -> a.key().equals(counter1Key), a -> {
|
||||
// key counter1 does not exist
|
||||
});
|
||||
//#get-response1
|
||||
|
||||
//#get-response2
|
||||
receive(ReceiveBuilder.
|
||||
match(GetSuccess.class, a -> a.key().equals(set1Key), a -> {
|
||||
GetSuccess<GSet<String>> g = a;
|
||||
Set<String> value = g.dataValue().getElements();
|
||||
}).
|
||||
match(GetFailure.class, a -> a.key().equals(set1Key), a -> {
|
||||
// read from 3 nodes failed within 1.second
|
||||
}).
|
||||
match(NotFound.class, a -> a.key().equals(set1Key), a -> {
|
||||
// key set1 does not exist
|
||||
}).build());
|
||||
b.match(GetSuccess.class, a -> a.key().equals(set1Key), a -> {
|
||||
GetSuccess<GSet<String>> g = a;
|
||||
Set<String> value = g.dataValue().getElements();
|
||||
}).
|
||||
match(GetFailure.class, a -> a.key().equals(set1Key), a -> {
|
||||
// read from 3 nodes failed within 1.second
|
||||
}).
|
||||
match(NotFound.class, a -> a.key().equals(set1Key), a -> {
|
||||
// key set1 does not exist
|
||||
});
|
||||
//#get-response2
|
||||
}
|
||||
};
|
||||
|
||||
//#get
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
//#get
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void demonstrateGetWithRequestContext() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
static
|
||||
//#get-request-context
|
||||
class DemonstrateGetWithRequestContext extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
|
||||
final ReadConsistency readTwo = new ReadFrom(2, Duration.create(3, SECONDS));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, a -> a.equals("get-count"), a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
Optional<Object> reqContext = Optional.of(sender());
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key,
|
||||
readTwo), self());
|
||||
})
|
||||
|
||||
//#get-request-context
|
||||
final ActorRef replicator = DistributedData.get(system).replicator();
|
||||
final ReadConsistency readTwo = new ReadFrom(2, Duration.create(3, SECONDS));
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
.match(GetSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
GetSuccess<PNCounter> g = a;
|
||||
long value = g.dataValue().getValue().longValue();
|
||||
replyTo.tell(value, self());
|
||||
})
|
||||
|
||||
receive(ReceiveBuilder.
|
||||
match(String.class, a -> a.equals("get-count"), a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
Optional<Object> reqContext = Optional.of(getTestActor());
|
||||
replicator.tell(new Replicator.Get<PNCounter>(counter1Key,
|
||||
readTwo), getTestActor());
|
||||
}).
|
||||
.match(GetFailure.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(-1L, self());
|
||||
})
|
||||
|
||||
match(GetSuccess.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
GetSuccess<PNCounter> g = a;
|
||||
long value = g.dataValue().getValue().longValue();
|
||||
replyTo.tell(value, getTestActor());
|
||||
}).
|
||||
|
||||
match(GetFailure.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(-1L, getTestActor());
|
||||
}).
|
||||
|
||||
match(NotFound.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(0L, getTestActor());
|
||||
}).build());
|
||||
//#get-request-context
|
||||
.match(NotFound.class, a -> a.key().equals(counter1Key), a -> {
|
||||
ActorRef replyTo = (ActorRef) a.getRequest().get();
|
||||
replyTo.tell(0L, self());
|
||||
})
|
||||
|
||||
.build();
|
||||
}
|
||||
};
|
||||
}
|
||||
//#get-request-context
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
abstract class MyActor extends AbstractActor {
|
||||
//#subscribe
|
||||
final ActorRef replicator = DistributedData.get(system).replicator();
|
||||
static
|
||||
//#subscribe
|
||||
class DemonstrateSubscribe extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
|
||||
BigInteger currentValue = BigInteger.valueOf(0);
|
||||
|
||||
public MyActor() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Changed.class, a -> a.key().equals(counter1Key), a -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Changed.class, a -> a.key().equals(counter1Key), a -> {
|
||||
Changed<PNCounter> g = a;
|
||||
currentValue = g.dataValue().getValue();
|
||||
}).
|
||||
|
||||
match(String.class, a -> a.equals("get-count"), a -> {
|
||||
})
|
||||
.match(String.class, a -> a.equals("get-count"), a -> {
|
||||
// incoming request to retrieve current value of the counter
|
||||
sender().tell(currentValue, sender());
|
||||
}).build());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
// subscribe to changes of the Counter1Key value
|
||||
replicator.tell(new Subscribe<PNCounter>(counter1Key, self()), ActorRef.noSender());
|
||||
}
|
||||
|
||||
//#subscribe
|
||||
}
|
||||
//#subscribe
|
||||
|
||||
@Test
|
||||
public void demonstrateDelete() {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
//#delete
|
||||
final ActorRef replicator = DistributedData.get(system).replicator();
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
static
|
||||
//#delete
|
||||
class DemonstrateDelete extends AbstractActor {
|
||||
final ActorRef replicator =
|
||||
DistributedData.get(getContext().system()).replicator();
|
||||
|
||||
final Key<PNCounter> counter1Key = PNCounterKey.create("counter1");
|
||||
final Key<ORSet<String>> set2Key = ORSetKey.create("set2");
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("demonstrate delete", msg -> {
|
||||
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key,
|
||||
Replicator.writeLocal()), getTestActor());
|
||||
|
||||
final WriteConsistency writeMajority =
|
||||
new WriteMajority(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key,
|
||||
writeMajority), getTestActor());
|
||||
//#delete
|
||||
}};
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key,
|
||||
Replicator.writeLocal()), self());
|
||||
|
||||
final WriteConsistency writeMajority =
|
||||
new WriteMajority(Duration.create(5, SECONDS));
|
||||
replicator.tell(new Delete<PNCounter>(counter1Key,
|
||||
writeMajority), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#delete
|
||||
|
||||
public void demonstratePNCounter() {
|
||||
//#pncounter
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import akka.dispatch.RequiresMessageQueue;
|
|||
import akka.testkit.AkkaSpec;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import docs.AbstractJavaTest;
|
||||
import docs.actor.MyBoundedUntypedActor;
|
||||
import docs.actor.MyUntypedActor;
|
||||
import docs.actorlambda.MyBoundedActor;
|
||||
import docs.actorlambda.MyActor;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.ExecutionContext;
|
||||
|
|
@ -17,7 +17,7 @@ import scala.concurrent.ExecutionContext;
|
|||
//#imports
|
||||
import akka.actor.*;
|
||||
//#imports
|
||||
|
||||
import akka.actor.AbstractActor.Receive;
|
||||
//#imports-prio
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
|
@ -52,7 +52,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
public void defineDispatcherInConfig() {
|
||||
//#defining-dispatcher-in-config
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyUntypedActor.class),
|
||||
system.actorOf(Props.create(MyActor.class),
|
||||
"myactor");
|
||||
//#defining-dispatcher-in-config
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
public void defineDispatcherInCode() {
|
||||
//#defining-dispatcher-in-code
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyUntypedActor.class).withDispatcher("my-dispatcher"),
|
||||
system.actorOf(Props.create(MyActor.class).withDispatcher("my-dispatcher"),
|
||||
"myactor3");
|
||||
//#defining-dispatcher-in-code
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void defineFixedPoolSizeDispatcher() {
|
||||
//#defining-fixed-pool-size-dispatcher
|
||||
ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class)
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class)
|
||||
.withDispatcher("blocking-io-dispatcher"));
|
||||
//#defining-fixed-pool-size-dispatcher
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void definePinnedDispatcher() {
|
||||
//#defining-pinned-dispatcher
|
||||
ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class)
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class)
|
||||
.withDispatcher("my-pinned-dispatcher"));
|
||||
//#defining-pinned-dispatcher
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
public void defineMailboxInConfig() {
|
||||
//#defining-mailbox-in-config
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyUntypedActor.class),
|
||||
system.actorOf(Props.create(MyActor.class),
|
||||
"priomailboxactor");
|
||||
//#defining-mailbox-in-config
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
public void defineMailboxInCode() {
|
||||
//#defining-mailbox-in-code
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyUntypedActor.class)
|
||||
system.actorOf(Props.create(MyActor.class)
|
||||
.withMailbox("prio-mailbox"));
|
||||
//#defining-mailbox-in-code
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
@Test
|
||||
public void usingARequiredMailbox() {
|
||||
ActorRef myActor =
|
||||
system.actorOf(Props.create(MyBoundedUntypedActor.class));
|
||||
system.actorOf(Props.create(MyBoundedActor.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -126,18 +126,21 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
JavaTestKit probe = new JavaTestKit(system);
|
||||
//#prio-dispatcher
|
||||
|
||||
class Demo extends UntypedActor {
|
||||
class Demo extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
{
|
||||
for (Object msg : new Object[] { "lowpriority", "lowpriority",
|
||||
"highpriority", "pigdog", "pigdog2", "pigdog3", "highpriority",
|
||||
PoisonPill.getInstance() }) {
|
||||
getSelf().tell(msg, getSelf());
|
||||
self().tell(msg, self());
|
||||
}
|
||||
}
|
||||
|
||||
public void onReceive(Object message) {
|
||||
log.info(message.toString());
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().matchAny(message -> {
|
||||
log.info(message.toString());
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,17 +169,20 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
JavaTestKit probe = new JavaTestKit(system);
|
||||
//#control-aware-dispatcher
|
||||
|
||||
class Demo extends UntypedActor {
|
||||
class Demo extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
{
|
||||
for (Object msg : new Object[] { "foo", "bar", new MyControlMessage(),
|
||||
PoisonPill.getInstance() }) {
|
||||
getSelf().tell(msg, getSelf());
|
||||
self().tell(msg, self());
|
||||
}
|
||||
}
|
||||
|
||||
public void onReceive(Object message) {
|
||||
log.info(message.toString());
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().matchAny(message -> {
|
||||
log.info(message.toString());
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,18 +232,18 @@ public class DispatcherDocTest extends AbstractJavaTest {
|
|||
|
||||
@Test
|
||||
public void requiredMailboxDispatcher() throws Exception {
|
||||
ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class)
|
||||
ActorRef myActor = system.actorOf(Props.create(MyActor.class)
|
||||
.withDispatcher("custom-dispatcher"));
|
||||
}
|
||||
|
||||
static
|
||||
//#require-mailbox-on-actor
|
||||
public class MySpecialActor extends UntypedActor implements
|
||||
public class MySpecialActor extends AbstractActor implements
|
||||
RequiresMessageQueue<MyUnboundedJMessageQueueSemantics> {
|
||||
//#require-mailbox-on-actor
|
||||
@Override
|
||||
public void onReceive(Object message) throws Exception {
|
||||
unhandled(message);
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
//#require-mailbox-on-actor
|
||||
// ...
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import akka.event.Logging.Debug;
|
|||
import docs.AbstractJavaTest;
|
||||
import org.junit.Test;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import scala.Option;
|
||||
import java.util.Optional;
|
||||
|
||||
//#imports-mdc
|
||||
import akka.event.Logging;
|
||||
|
|
@ -80,15 +80,18 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
}
|
||||
}
|
||||
|
||||
static class Listener extends UntypedActor {
|
||||
static class Listener extends AbstractActor {
|
||||
@Override
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof Jazz) {
|
||||
System.out.printf("%s is listening to: %s%n", self().path().name(), message);
|
||||
} else if (message instanceof Electronic) {
|
||||
System.out.printf("%s is listening to: %s%n", self().path().name(), message);
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Jazz.class, msg ->
|
||||
System.out.printf("%s is listening to: %s%n", self().path().name(), msg)
|
||||
)
|
||||
.match(Electronic.class, msg ->
|
||||
System.out.printf("%s is listening to: %s%n", self().path().name(), msg)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
//#superclass-subscription-eventstream
|
||||
|
||||
|
|
@ -148,7 +151,7 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
//#my-actor
|
||||
class MyActor extends UntypedActor {
|
||||
class MyActor extends AbstractActor {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
|
||||
@Override
|
||||
|
|
@ -157,68 +160,86 @@ public class LoggingDocTest extends AbstractJavaTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Option<Object> message) {
|
||||
public void preRestart(Throwable reason, Optional<Object> message) {
|
||||
log.error(reason, "Restarting due to [{}] when processing [{}]",
|
||||
reason.getMessage(), message.isDefined() ? message.get() : "");
|
||||
reason.getMessage(), message.isPresent() ? message.get() : "");
|
||||
}
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("test")) {
|
||||
log.info("Received test");
|
||||
} else {
|
||||
log.warning("Received unknown message: {}", message);
|
||||
}
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("test", msg ->
|
||||
log.info("Received test")
|
||||
)
|
||||
.matchAny(msg ->
|
||||
log.warning("Received unknown message: {}", msg)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
//#my-actor
|
||||
|
||||
//#mdc-actor
|
||||
class MdcActor extends UntypedActor {
|
||||
class MdcActor extends AbstractActor {
|
||||
|
||||
final DiagnosticLoggingAdapter log = Logging.getLogger(this);
|
||||
|
||||
public void onReceive(Object message) {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(msg -> {
|
||||
Map<String, Object> mdc;
|
||||
mdc = new HashMap<String, Object>();
|
||||
mdc.put("requestId", 1234);
|
||||
mdc.put("visitorId", 5678);
|
||||
log.setMDC(mdc);
|
||||
|
||||
Map<String, Object> mdc;
|
||||
mdc = new HashMap<String, Object>();
|
||||
mdc.put("requestId", 1234);
|
||||
mdc.put("visitorId", 5678);
|
||||
log.setMDC(mdc);
|
||||
log.info("Starting new request");
|
||||
|
||||
log.info("Starting new request");
|
||||
|
||||
log.clearMDC();
|
||||
log.clearMDC();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
//#mdc-actor
|
||||
|
||||
//#my-event-listener
|
||||
class MyEventListener extends UntypedActor {
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof InitializeLogger) {
|
||||
getSender().tell(Logging.loggerInitialized(), getSelf());
|
||||
} else if (message instanceof Error) {
|
||||
// ...
|
||||
} else if (message instanceof Warning) {
|
||||
// ...
|
||||
} else if (message instanceof Info) {
|
||||
// ...
|
||||
} else if (message instanceof Debug) {
|
||||
// ...
|
||||
}
|
||||
class MyEventListener extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(InitializeLogger.class, msg -> {
|
||||
sender().tell(Logging.loggerInitialized(), self());
|
||||
})
|
||||
.match(Error.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(Warning.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(Info.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.match(Debug.class, msg -> {
|
||||
// ...
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#my-event-listener
|
||||
|
||||
static
|
||||
//#deadletter-actor
|
||||
public class DeadLetterActor extends UntypedActor {
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof DeadLetter) {
|
||||
System.out.println(message);
|
||||
}
|
||||
public class DeadLetterActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(DeadLetter.class, msg -> {
|
||||
System.out.println(msg);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#deadletter-actor
|
||||
|
|
|
|||
|
|
@ -57,11 +57,16 @@ public class ExtensionDocTest extends AbstractJavaTest {
|
|||
|
||||
static
|
||||
//#extension-usage-actor
|
||||
public class MyActor extends UntypedActor {
|
||||
public void onReceive(Object msg) {
|
||||
// typically you would use static import of the
|
||||
// CountExtension.CountExtensionProvider field
|
||||
CountExtension.CountExtensionProvider.get(getContext().system()).increment();
|
||||
public class MyActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(msg -> {
|
||||
// typically you would use static import of the
|
||||
// CountExtension.CountExtensionProvider field
|
||||
CountExtension.CountExtensionProvider.get(getContext().system()).increment();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ import akka.actor.AbstractExtensionId;
|
|||
import akka.actor.ExtensionIdProvider;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.ExtendedActorSystem;
|
||||
import docs.AbstractJavaTest;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import com.typesafe.config.Config;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
//#imports
|
||||
|
||||
import akka.actor.UntypedActor;
|
||||
import docs.AbstractJavaTest;
|
||||
import akka.actor.AbstractActor;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SettingsExtensionDocTest extends AbstractJavaTest {
|
||||
|
|
@ -60,7 +60,7 @@ public class SettingsExtensionDocTest extends AbstractJavaTest {
|
|||
|
||||
static
|
||||
//#extension-usage-actor
|
||||
public class MyActor extends UntypedActor {
|
||||
public class MyActor extends AbstractActor {
|
||||
// typically you would use static import of the Settings.SettingsProvider field
|
||||
final SettingsImpl settings =
|
||||
Settings.SettingsProvider.get(getContext().system());
|
||||
|
|
@ -73,7 +73,9 @@ public class SettingsExtensionDocTest extends AbstractJavaTest {
|
|||
return new Connection();
|
||||
}
|
||||
|
||||
public void onReceive(Object msg) {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return AbstractActor.emptyBehavior();
|
||||
}
|
||||
//#extension-usage-actor
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ import org.junit.Test;
|
|||
import akka.testkit.AkkaSpec;
|
||||
import akka.actor.Status.Failure;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import akka.pattern.Patterns;
|
||||
|
|
@ -656,20 +656,21 @@ public class FutureDocTest extends AbstractJavaTest {
|
|||
|
||||
|
||||
|
||||
public static class MyActor extends UntypedActor {
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof String) {
|
||||
getSender().tell(((String) message).toUpperCase(), getSelf());
|
||||
} else if (message instanceof Integer) {
|
||||
int i = ((Integer) message).intValue();
|
||||
if (i < 0) {
|
||||
getSender().tell(new Failure(new ArithmeticException("Negative values not supported")), getSelf());
|
||||
} else {
|
||||
getSender().tell(i, getSelf());
|
||||
}
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
public static class MyActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(String.class, msg -> {
|
||||
sender().tell(msg.toUpperCase(), self());
|
||||
})
|
||||
.match(Integer.class, i -> {
|
||||
if (i < 0) {
|
||||
sender().tell(new Failure(new ArithmeticException("Negative values not supported")), self());
|
||||
} else {
|
||||
sender().tell(i, self());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
//#imports
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -24,65 +24,63 @@ import akka.util.ByteString;
|
|||
|
||||
public class IODocTest {
|
||||
|
||||
static public class Demo extends UntypedActor {
|
||||
static public class Demo extends AbstractActor {
|
||||
ActorRef connectionActor = null;
|
||||
ActorRef listener = getSelf();
|
||||
ActorRef listener = self();
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
if ("connect".equals(msg)) {
|
||||
//#manager
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
//#manager
|
||||
//#connect
|
||||
final InetSocketAddress remoteAddr = new InetSocketAddress("127.0.0.1",
|
||||
12345);
|
||||
tcp.tell(TcpMessage.connect(remoteAddr), getSelf());
|
||||
//#connect
|
||||
//#connect-with-options
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
|
||||
1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.keepAlive(true));
|
||||
tcp.tell(TcpMessage.connect(remoteAddr, localAddr, options, null, false), getSelf());
|
||||
//#connect-with-options
|
||||
} else
|
||||
//#connected
|
||||
if (msg instanceof Tcp.Connected) {
|
||||
final Tcp.Connected conn = (Tcp.Connected) msg;
|
||||
connectionActor = getSender();
|
||||
connectionActor.tell(TcpMessage.register(listener), getSelf());
|
||||
}
|
||||
//#connected
|
||||
else
|
||||
//#received
|
||||
if (msg instanceof Tcp.Received) {
|
||||
final Tcp.Received recv = (Tcp.Received) msg;
|
||||
final ByteString data = recv.data();
|
||||
// and do something with the received data ...
|
||||
} else if (msg instanceof Tcp.CommandFailed) {
|
||||
final Tcp.CommandFailed failed = (Tcp.CommandFailed) msg;
|
||||
final Tcp.Command command = failed.cmd();
|
||||
// react to failed connect, bind, write, etc.
|
||||
} else if (msg instanceof Tcp.ConnectionClosed) {
|
||||
final Tcp.ConnectionClosed closed = (Tcp.ConnectionClosed) msg;
|
||||
if (closed.isAborted()) {
|
||||
// handle close reasons like this
|
||||
}
|
||||
}
|
||||
//#received
|
||||
else
|
||||
if ("bind".equals(msg)) {
|
||||
final ActorRef handler = getSelf();
|
||||
//#bind
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
|
||||
1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.reuseAddress(true));
|
||||
tcp.tell(TcpMessage.bind(handler, localAddr, 10, options, false), getSelf());
|
||||
//#bind
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("connect", msg -> {
|
||||
//#manager
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
//#manager
|
||||
//#connect
|
||||
final InetSocketAddress remoteAddr = new InetSocketAddress("127.0.0.1",
|
||||
12345);
|
||||
tcp.tell(TcpMessage.connect(remoteAddr), self());
|
||||
//#connect
|
||||
//#connect-with-options
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
|
||||
1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.keepAlive(true));
|
||||
tcp.tell(TcpMessage.connect(remoteAddr, localAddr, options, null, false), self());
|
||||
//#connect-with-options
|
||||
})
|
||||
//#connected
|
||||
.match(Tcp.Connected.class, conn -> {
|
||||
connectionActor = sender();
|
||||
connectionActor.tell(TcpMessage.register(listener), self());
|
||||
})
|
||||
//#connected
|
||||
//#received
|
||||
.match(Tcp.Received.class, recv -> {
|
||||
final ByteString data = recv.data();
|
||||
// and do something with the received data ...
|
||||
})
|
||||
.match(Tcp.CommandFailed.class, failed -> {
|
||||
final Tcp.Command command = failed.cmd();
|
||||
// react to failed connect, bind, write, etc.
|
||||
})
|
||||
.match(Tcp.ConnectionClosed.class, closed -> {
|
||||
if (closed.isAborted()) {
|
||||
// handle close reasons like this
|
||||
}
|
||||
})
|
||||
//#received
|
||||
.matchEquals("bind", msg -> {
|
||||
final ActorRef handler = self();
|
||||
//#bind
|
||||
final ActorRef tcp = Tcp.get(system).manager();
|
||||
final InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
|
||||
1234);
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
options.add(TcpSO.reuseAddress(true));
|
||||
tcp.tell(TcpMessage.bind(handler, localAddr, 10, options, false), self());
|
||||
//#bind
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@ public class JavaReadBackPressure {
|
|||
//#pull-accepting
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof Tcp.Bound) {
|
||||
listener = getSender();
|
||||
listener = sender();
|
||||
// Accept connections one by one
|
||||
listener.tell(TcpMessage.resumeAccepting(1), getSelf());
|
||||
listener.tell(TcpMessage.resumeAccepting(1), self());
|
||||
} else if (message instanceof Tcp.Connected) {
|
||||
ActorRef handler = getContext().actorOf(Props.create(PullEcho.class, getSender()));
|
||||
getSender().tell(TcpMessage.register(handler), getSelf());
|
||||
ActorRef handler = getContext().actorOf(Props.create(PullEcho.class, sender()));
|
||||
sender().tell(TcpMessage.register(handler), self());
|
||||
// Resume accepting connections
|
||||
listener.tell(TcpMessage.resumeAccepting(1), getSelf());
|
||||
listener.tell(TcpMessage.resumeAccepting(1), self());
|
||||
}
|
||||
}
|
||||
//#pull-accepting
|
||||
|
|
@ -43,8 +43,8 @@ public class JavaReadBackPressure {
|
|||
tcp = Tcp.get(getContext().system()).manager();
|
||||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
tcp.tell(
|
||||
TcpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0), 100, options, true),
|
||||
getSelf()
|
||||
TcpMessage.bind(self(), new InetSocketAddress("localhost", 0), 100, options, true),
|
||||
self()
|
||||
);
|
||||
//#pull-mode-bind
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ public class JavaReadBackPressure {
|
|||
final List<Inet.SocketOption> options = new ArrayList<Inet.SocketOption>();
|
||||
tcp.tell(
|
||||
TcpMessage.connect(new InetSocketAddress("localhost", 3000), null, options, null, true),
|
||||
getSelf()
|
||||
self()
|
||||
);
|
||||
//#pull-mode-connect
|
||||
}
|
||||
|
|
@ -73,16 +73,16 @@ public class JavaReadBackPressure {
|
|||
//#pull-reading-echo
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
connection.tell(TcpMessage.resumeReading(), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof Tcp.Received) {
|
||||
ByteString data = ((Tcp.Received) message).data();
|
||||
connection.tell(TcpMessage.write(data, new Ack()), getSelf());
|
||||
connection.tell(TcpMessage.write(data, new Ack()), self());
|
||||
} else if (message instanceof Ack) {
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
connection.tell(TcpMessage.resumeReading(), self());
|
||||
}
|
||||
}
|
||||
//#pull-reading-echo
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class JavaUdpMulticast {
|
|||
final ActorRef mgr = Udp.get(getContext().system()).getManager();
|
||||
// listen for datagrams on this address
|
||||
InetSocketAddress endpoint = new InetSocketAddress(port);
|
||||
mgr.tell(UdpMessage.bind(getSelf(), endpoint, options), getSelf());
|
||||
mgr.tell(UdpMessage.bind(self(), endpoint, options), self());
|
||||
//#bind
|
||||
}
|
||||
|
||||
|
|
@ -82,12 +82,12 @@ public class JavaUdpMulticast {
|
|||
if (msg instanceof Udp.Bound) {
|
||||
final Udp.Bound b = (Udp.Bound) msg;
|
||||
log.info("Bound to {}", b.localAddress());
|
||||
sink.tell(b, getSelf());
|
||||
sink.tell(b, self());
|
||||
} else if (msg instanceof Udp.Received) {
|
||||
final Udp.Received r = (Udp.Received) msg;
|
||||
final String txt = r.data().decodeString("utf-8");
|
||||
log.info("Received '{}' from {}", txt, r.sender());
|
||||
sink.tell(txt, getSelf());
|
||||
sink.tell(txt, self());
|
||||
} else unhandled(msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ public class JavaUdpMulticast {
|
|||
options.add(new Inet6ProtocolFamily());
|
||||
|
||||
final ActorRef mgr = Udp.get(getContext().system()).getManager();
|
||||
mgr.tell(UdpMessage.simpleSender(options), getSelf());
|
||||
mgr.tell(UdpMessage.simpleSender(options), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -118,7 +118,7 @@ public class JavaUdpMulticast {
|
|||
if (msg instanceof Udp.SimpleSenderReady) {
|
||||
InetSocketAddress remote = new InetSocketAddress(group + "%" + iface, port);
|
||||
log.info("Sending message to " + remote);
|
||||
getSender().tell(UdpMessage.send(ByteString.fromString(message), remote), getSelf());
|
||||
sender().tell(UdpMessage.send(ByteString.fromString(message), remote), self());
|
||||
} else unhandled(msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ public class UdpConnectedDocTest {
|
|||
|
||||
static public class Demo extends UntypedActor {
|
||||
ActorRef connectionActor = null;
|
||||
ActorRef handler = getSelf();
|
||||
ActorSystem system = context().system();
|
||||
ActorRef handler = self();
|
||||
ActorSystem system = getContext().system();
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
|
|
@ -38,7 +38,7 @@ public class UdpConnectedDocTest {
|
|||
//#connect
|
||||
final InetSocketAddress remoteAddr =
|
||||
new InetSocketAddress("127.0.0.1", 12345);
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr), getSelf());
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr), self());
|
||||
//#connect
|
||||
//#connect-with-options
|
||||
final InetSocketAddress localAddr =
|
||||
|
|
@ -46,13 +46,13 @@ public class UdpConnectedDocTest {
|
|||
final List<Inet.SocketOption> options =
|
||||
new ArrayList<Inet.SocketOption>();
|
||||
options.add(UdpSO.broadcast(true));
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr, localAddr, options), getSelf());
|
||||
udp.tell(UdpConnectedMessage.connect(handler, remoteAddr, localAddr, options), self());
|
||||
//#connect-with-options
|
||||
} else
|
||||
//#connected
|
||||
if (msg instanceof UdpConnected.Connected) {
|
||||
final UdpConnected.Connected conn = (UdpConnected.Connected) msg;
|
||||
connectionActor = getSender(); // Save the worker ref for later use
|
||||
connectionActor = sender(); // Save the worker ref for later use
|
||||
}
|
||||
//#connected
|
||||
else
|
||||
|
|
@ -73,7 +73,7 @@ public class UdpConnectedDocTest {
|
|||
if ("send".equals(msg)) {
|
||||
ByteString data = ByteString.empty();
|
||||
//#send
|
||||
connectionActor.tell(UdpConnectedMessage.send(data), getSelf());
|
||||
connectionActor.tell(UdpConnectedMessage.send(data), self());
|
||||
//#send
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,15 +29,15 @@ public class UdpDocTest {
|
|||
|
||||
// request creation of a SimpleSender
|
||||
final ActorRef mgr = Udp.get(getContext().system()).getManager();
|
||||
mgr.tell(UdpMessage.simpleSender(), getSelf());
|
||||
mgr.tell(UdpMessage.simpleSender(), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
if (msg instanceof Udp.SimpleSenderReady) {
|
||||
getContext().become(ready(getSender()));
|
||||
getContext().become(ready(sender()));
|
||||
//#sender
|
||||
getSender().tell(UdpMessage.send(ByteString.fromString("hello"), remote), getSelf());
|
||||
sender().tell(UdpMessage.send(ByteString.fromString("hello"), remote), self());
|
||||
//#sender
|
||||
} else unhandled(msg);
|
||||
}
|
||||
|
|
@ -48,10 +48,10 @@ public class UdpDocTest {
|
|||
public void apply(Object msg) throws Exception {
|
||||
if (msg instanceof String) {
|
||||
final String str = (String) msg;
|
||||
send.tell(UdpMessage.send(ByteString.fromString(str), remote), getSelf());
|
||||
send.tell(UdpMessage.send(ByteString.fromString(str), remote), self());
|
||||
//#sender
|
||||
if (str.equals("world")) {
|
||||
send.tell(PoisonPill.getInstance(), getSelf());
|
||||
send.tell(PoisonPill.getInstance(), self());
|
||||
}
|
||||
//#sender
|
||||
|
||||
|
|
@ -72,8 +72,8 @@ public class UdpDocTest {
|
|||
// request creation of a bound listen socket
|
||||
final ActorRef mgr = Udp.get(getContext().system()).getManager();
|
||||
mgr.tell(
|
||||
UdpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0)),
|
||||
getSelf());
|
||||
UdpMessage.bind(self(), new InetSocketAddress("localhost", 0)),
|
||||
self());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -81,9 +81,9 @@ public class UdpDocTest {
|
|||
if (msg instanceof Udp.Bound) {
|
||||
final Udp.Bound b = (Udp.Bound) msg;
|
||||
//#listener
|
||||
nextActor.tell(b.localAddress(), getSender());
|
||||
nextActor.tell(b.localAddress(), sender());
|
||||
//#listener
|
||||
getContext().become(ready(getSender()));
|
||||
getContext().become(ready(sender()));
|
||||
} else unhandled(msg);
|
||||
}
|
||||
|
||||
|
|
@ -94,19 +94,19 @@ public class UdpDocTest {
|
|||
if (msg instanceof Udp.Received) {
|
||||
final Udp.Received r = (Udp.Received) msg;
|
||||
// echo server example: send back the data
|
||||
socket.tell(UdpMessage.send(r.data(), r.sender()), getSelf());
|
||||
socket.tell(UdpMessage.send(r.data(), r.sender()), self());
|
||||
// or do some processing and forward it on
|
||||
final Object processed = // parse data etc., e.g. using PipelineStage
|
||||
//#listener
|
||||
r.data().utf8String();
|
||||
//#listener
|
||||
nextActor.tell(processed, getSelf());
|
||||
nextActor.tell(processed, self());
|
||||
|
||||
} else if (msg.equals(UdpMessage.unbind())) {
|
||||
socket.tell(msg, getSelf());
|
||||
socket.tell(msg, self());
|
||||
|
||||
} else if (msg instanceof Udp.Unbound) {
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
|
||||
} else unhandled(msg);
|
||||
}
|
||||
|
|
@ -124,17 +124,17 @@ public class UdpDocTest {
|
|||
|
||||
// create a restricted a.k.a. “connected” socket
|
||||
final ActorRef mgr = UdpConnected.get(getContext().system()).getManager();
|
||||
mgr.tell(UdpConnectedMessage.connect(getSelf(), remote), getSelf());
|
||||
mgr.tell(UdpConnectedMessage.connect(self(), remote), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) {
|
||||
if (msg instanceof UdpConnected.Connected) {
|
||||
getContext().become(ready(getSender()));
|
||||
getContext().become(ready(sender()));
|
||||
//#connected
|
||||
getSender()
|
||||
sender()
|
||||
.tell(UdpConnectedMessage.send(ByteString.fromString("hello")),
|
||||
getSelf());
|
||||
self());
|
||||
//#connected
|
||||
} else unhandled(msg);
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ public class UdpDocTest {
|
|||
if (r.data().utf8String().equals("hello")) {
|
||||
connection.tell(
|
||||
UdpConnectedMessage.send(ByteString.fromString("world")),
|
||||
getSelf());
|
||||
self());
|
||||
}
|
||||
// #connected
|
||||
|
||||
|
|
@ -158,13 +158,13 @@ public class UdpDocTest {
|
|||
final String str = (String) msg;
|
||||
connection
|
||||
.tell(UdpConnectedMessage.send(ByteString.fromString(str)),
|
||||
getSelf());
|
||||
self());
|
||||
|
||||
} else if (msg.equals(UdpConnectedMessage.disconnect())) {
|
||||
connection.tell(msg, getSelf());
|
||||
connection.tell(msg, self());
|
||||
|
||||
} else if (msg instanceof UdpConnected.Disconnected) {
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
|
||||
} else unhandled(msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.LinkedList;
|
|||
import java.util.Queue;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.io.Tcp.CommandFailed;
|
||||
|
|
@ -19,14 +19,13 @@ import akka.io.Tcp.Received;
|
|||
import akka.io.Tcp.Write;
|
||||
import akka.io.Tcp.WritingResumed;
|
||||
import akka.io.TcpMessage;
|
||||
import akka.japi.Procedure;
|
||||
import akka.util.ByteString;
|
||||
|
||||
//#echo-handler
|
||||
public class EchoHandler extends UntypedActor {
|
||||
public class EchoHandler extends AbstractActor {
|
||||
|
||||
final LoggingAdapter log = Logging
|
||||
.getLogger(getContext().system(), getSelf());
|
||||
.getLogger(getContext().system(), self());
|
||||
|
||||
final ActorRef connection;
|
||||
final InetSocketAddress remote;
|
||||
|
|
@ -35,6 +34,13 @@ public class EchoHandler extends UntypedActor {
|
|||
public static final long HIGH_WATERMARK = MAX_STORED * 5 / 10;
|
||||
public static final long LOW_WATERMARK = MAX_STORED * 2 / 10;
|
||||
|
||||
private long transferred;
|
||||
private int storageOffset = 0;
|
||||
private long stored = 0;
|
||||
private Queue<ByteString> storage = new LinkedList<ByteString>();
|
||||
|
||||
private boolean suspended = false;
|
||||
|
||||
private static class Ack implements Event {
|
||||
public final int ack;
|
||||
public Ack(int ack) {
|
||||
|
|
@ -45,6 +51,8 @@ public class EchoHandler extends UntypedActor {
|
|||
public EchoHandler(ActorRef connection, InetSocketAddress remote) {
|
||||
this.connection = connection;
|
||||
this.remote = remote;
|
||||
|
||||
writing = writing();
|
||||
|
||||
// sign death pact: this actor stops when the connection is closed
|
||||
getContext().watch(connection);
|
||||
|
|
@ -52,138 +60,136 @@ public class EchoHandler extends UntypedActor {
|
|||
// start out in optimistic write-through mode
|
||||
getContext().become(writing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return writing;
|
||||
}
|
||||
|
||||
private final Procedure<Object> writing = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object msg) throws Exception {
|
||||
if (msg instanceof Received) {
|
||||
final ByteString data = ((Received) msg).data();
|
||||
connection.tell(TcpMessage.write(data, new Ack(currentOffset())), getSelf());
|
||||
private final Receive writing;
|
||||
|
||||
private Receive writing() {
|
||||
return receiveBuilder()
|
||||
.match(Received.class, msg -> {
|
||||
final ByteString data = msg.data();
|
||||
connection.tell(TcpMessage.write(data, new Ack(currentOffset())), self());
|
||||
buffer(data);
|
||||
|
||||
} else if (msg instanceof Integer) {
|
||||
acknowledge((Integer) msg);
|
||||
|
||||
} else if (msg instanceof CommandFailed) {
|
||||
final Write w = (Write) ((CommandFailed) msg).cmd();
|
||||
connection.tell(TcpMessage.resumeWriting(), getSelf());
|
||||
})
|
||||
.match(Integer.class, msg -> {
|
||||
acknowledge(msg);
|
||||
})
|
||||
.match(CommandFailed.class, msg -> {
|
||||
final Write w = (Write) msg.cmd();
|
||||
connection.tell(TcpMessage.resumeWriting(), self());
|
||||
getContext().become(buffering((Ack) w.ack()));
|
||||
|
||||
} else if (msg instanceof ConnectionClosed) {
|
||||
final ConnectionClosed cl = (ConnectionClosed) msg;
|
||||
if (cl.isPeerClosed()) {
|
||||
})
|
||||
.match(ConnectionClosed.class, msg -> {
|
||||
if (msg.isPeerClosed()) {
|
||||
if (storage.isEmpty()) {
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
} else {
|
||||
getContext().become(closing);
|
||||
getContext().become(closing());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
//#buffering
|
||||
protected Procedure<Object> buffering(final Ack nack) {
|
||||
return new Procedure<Object>() {
|
||||
|
||||
final static class BufferingState {
|
||||
int toAck = 10;
|
||||
boolean peerClosed = false;
|
||||
}
|
||||
|
||||
protected Receive buffering(final Ack nack) {
|
||||
final BufferingState state = new BufferingState();
|
||||
|
||||
return receiveBuilder()
|
||||
.match(Received.class, msg -> {
|
||||
buffer(msg.data());
|
||||
|
||||
private int toAck = 10;
|
||||
private boolean peerClosed = false;
|
||||
})
|
||||
.match(WritingResumed.class, msg -> {
|
||||
writeFirst();
|
||||
|
||||
@Override
|
||||
public void apply(Object msg) throws Exception {
|
||||
if (msg instanceof Received) {
|
||||
buffer(((Received) msg).data());
|
||||
})
|
||||
.match(ConnectionClosed.class, msg -> {
|
||||
if (msg.isPeerClosed())
|
||||
state.peerClosed = true;
|
||||
else
|
||||
getContext().stop(self());
|
||||
|
||||
} else if (msg instanceof WritingResumed) {
|
||||
writeFirst();
|
||||
})
|
||||
.match(Integer.class, ack -> {
|
||||
acknowledge(ack);
|
||||
|
||||
} else if (msg instanceof ConnectionClosed) {
|
||||
if (((ConnectionClosed) msg).isPeerClosed())
|
||||
peerClosed = true;
|
||||
else
|
||||
getContext().stop(getSelf());
|
||||
if (ack >= nack.ack) {
|
||||
// otherwise it was the ack of the last successful write
|
||||
|
||||
} else if (msg instanceof Integer) {
|
||||
final int ack = (Integer) msg;
|
||||
acknowledge(ack);
|
||||
if (storage.isEmpty()) {
|
||||
if (state.peerClosed)
|
||||
getContext().stop(self());
|
||||
else
|
||||
getContext().become(writing);
|
||||
|
||||
if (ack >= nack.ack) {
|
||||
// otherwise it was the ack of the last successful write
|
||||
|
||||
if (storage.isEmpty()) {
|
||||
if (peerClosed)
|
||||
getContext().stop(getSelf());
|
||||
} else {
|
||||
if (state.toAck > 0) {
|
||||
// stay in ACK-based mode for a short while
|
||||
writeFirst();
|
||||
--state.toAck;
|
||||
} else {
|
||||
// then return to NACK-based again
|
||||
writeAll();
|
||||
if (state.peerClosed)
|
||||
getContext().become(closing());
|
||||
else
|
||||
getContext().become(writing);
|
||||
|
||||
} else {
|
||||
if (toAck > 0) {
|
||||
// stay in ACK-based mode for a short while
|
||||
writeFirst();
|
||||
--toAck;
|
||||
} else {
|
||||
// then return to NACK-based again
|
||||
writeAll();
|
||||
if (peerClosed)
|
||||
getContext().become(closing);
|
||||
else
|
||||
getContext().become(writing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#buffering
|
||||
|
||||
//#closing
|
||||
protected Procedure<Object> closing = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object msg) throws Exception {
|
||||
if (msg instanceof CommandFailed) {
|
||||
protected Receive closing() {
|
||||
return receiveBuilder()
|
||||
.match(CommandFailed.class, msg -> {
|
||||
// the command can only have been a Write
|
||||
connection.tell(TcpMessage.resumeWriting(), getSelf());
|
||||
getContext().become(closeResend, false);
|
||||
} else if (msg instanceof Integer) {
|
||||
acknowledge((Integer) msg);
|
||||
connection.tell(TcpMessage.resumeWriting(), self());
|
||||
getContext().become(closeResend(), false);
|
||||
})
|
||||
.match(Integer.class, msg -> {
|
||||
acknowledge(msg);
|
||||
if (storage.isEmpty())
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
};
|
||||
getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
protected Procedure<Object> closeResend = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object msg) throws Exception {
|
||||
if (msg instanceof WritingResumed) {
|
||||
protected Receive closeResend() {
|
||||
return receiveBuilder()
|
||||
.match(WritingResumed.class, msg -> {
|
||||
writeAll();
|
||||
getContext().unbecome();
|
||||
} else if (msg instanceof Integer) {
|
||||
acknowledge((Integer) msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.match(Integer.class, msg -> {
|
||||
acknowledge(msg);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#closing
|
||||
|
||||
//#storage-omitted
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
// this method is not used due to become()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postStop() {
|
||||
log.info("transferred {} bytes from/to [{}]", transferred, remote);
|
||||
}
|
||||
|
||||
private long transferred;
|
||||
private int storageOffset = 0;
|
||||
private long stored = 0;
|
||||
private Queue<ByteString> storage = new LinkedList<ByteString>();
|
||||
|
||||
private boolean suspended = false;
|
||||
|
||||
//#helpers
|
||||
protected void buffer(ByteString data) {
|
||||
storage.add(data);
|
||||
|
|
@ -191,11 +197,11 @@ public class EchoHandler extends UntypedActor {
|
|||
|
||||
if (stored > MAX_STORED) {
|
||||
log.warning("drop connection to [{}] (buffer overrun)", remote);
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
|
||||
} else if (stored > HIGH_WATERMARK) {
|
||||
log.debug("suspending reading at {}", currentOffset());
|
||||
connection.tell(TcpMessage.suspendReading(), getSelf());
|
||||
connection.tell(TcpMessage.suspendReading(), self());
|
||||
suspended = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +217,7 @@ public class EchoHandler extends UntypedActor {
|
|||
|
||||
if (suspended && stored < LOW_WATERMARK) {
|
||||
log.debug("resuming reading");
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
connection.tell(TcpMessage.resumeReading(), self());
|
||||
suspended = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -224,12 +230,12 @@ public class EchoHandler extends UntypedActor {
|
|||
protected void writeAll() {
|
||||
int i = 0;
|
||||
for (ByteString data : storage) {
|
||||
connection.tell(TcpMessage.write(data, new Ack(storageOffset + i++)), getSelf());
|
||||
connection.tell(TcpMessage.write(data, new Ack(storageOffset + i++)), self());
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeFirst() {
|
||||
connection.tell(TcpMessage.write(storage.peek(), new Ack(storageOffset)), getSelf());
|
||||
connection.tell(TcpMessage.write(storage.peek(), new Ack(storageOffset)), self());
|
||||
}
|
||||
|
||||
//#storage-omitted
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.net.InetSocketAddress;
|
|||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.SupervisorStrategy;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.io.Tcp;
|
||||
|
|
@ -19,10 +19,10 @@ import akka.io.Tcp.CommandFailed;
|
|||
import akka.io.Tcp.Connected;
|
||||
import akka.io.TcpMessage;
|
||||
|
||||
public class EchoManager extends UntypedActor {
|
||||
public class EchoManager extends AbstractActor {
|
||||
|
||||
final LoggingAdapter log = Logging
|
||||
.getLogger(getContext().system(), getSelf());
|
||||
.getLogger(getContext().system(), self());
|
||||
|
||||
final Class<?> handlerClass;
|
||||
|
||||
|
|
@ -41,41 +41,42 @@ public class EchoManager extends UntypedActor {
|
|||
final ActorRef tcpManager = Tcp.get(getContext().system()).manager();
|
||||
//#manager
|
||||
tcpManager.tell(
|
||||
TcpMessage.bind(getSelf(), new InetSocketAddress("localhost", 0), 100),
|
||||
getSelf());
|
||||
TcpMessage.bind(self(), new InetSocketAddress("localhost", 0), 100),
|
||||
self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRestart(Throwable arg0) throws Exception {
|
||||
// do not restart
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof Bound) {
|
||||
log.info("listening on [{}]", ((Bound) msg).localAddress());
|
||||
} else if (msg instanceof Tcp.CommandFailed) {
|
||||
final CommandFailed failed = (CommandFailed) msg;
|
||||
if (failed.cmd() instanceof Bind) {
|
||||
log.warning("cannot bind to [{}]", ((Bind) failed.cmd()).localAddress());
|
||||
getContext().stop(getSelf());
|
||||
} else {
|
||||
log.warning("unknown command failed [{}]", failed.cmd());
|
||||
}
|
||||
} else
|
||||
if (msg instanceof Connected) {
|
||||
final Connected conn = (Connected) msg;
|
||||
log.info("received connection from [{}]", conn.remoteAddress());
|
||||
final ActorRef connection = getSender();
|
||||
final ActorRef handler = getContext().actorOf(
|
||||
Props.create(handlerClass, connection, conn.remoteAddress()));
|
||||
//#echo-manager
|
||||
connection.tell(TcpMessage.register(handler,
|
||||
true, // <-- keepOpenOnPeerClosed flag
|
||||
true), getSelf());
|
||||
//#echo-manager
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Bound.class, msg -> {
|
||||
log.info("listening on [{}]", msg.localAddress());
|
||||
})
|
||||
.match(Tcp.CommandFailed.class, failed -> {
|
||||
if (failed.cmd() instanceof Bind) {
|
||||
log.warning("cannot bind to [{}]", ((Bind) failed.cmd()).localAddress());
|
||||
getContext().stop(self());
|
||||
} else {
|
||||
log.warning("unknown command failed [{}]", failed.cmd());
|
||||
}
|
||||
})
|
||||
.match(Connected.class, conn -> {
|
||||
log.info("received connection from [{}]", conn.remoteAddress());
|
||||
final ActorRef connection = sender();
|
||||
final ActorRef handler = getContext().actorOf(
|
||||
Props.create(handlerClass, connection, conn.remoteAddress()));
|
||||
//#echo-manager
|
||||
connection.tell(TcpMessage.register(handler,
|
||||
true, // <-- keepOpenOnPeerClosed flag
|
||||
true), self());
|
||||
//#echo-manager
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import java.net.InetSocketAddress;
|
|||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.io.Tcp;
|
||||
import akka.io.Tcp.Bound;
|
||||
import akka.io.Tcp.CommandFailed;
|
||||
|
|
@ -34,7 +34,7 @@ public class IODocTest extends AbstractJavaTest {
|
|||
|
||||
static
|
||||
//#server
|
||||
public class Server extends UntypedActor {
|
||||
public class Server extends AbstractActor {
|
||||
|
||||
final ActorRef manager;
|
||||
|
||||
|
|
@ -49,25 +49,28 @@ public class IODocTest extends AbstractJavaTest {
|
|||
@Override
|
||||
public void preStart() throws Exception {
|
||||
final ActorRef tcp = Tcp.get(getContext().system()).manager();
|
||||
tcp.tell(TcpMessage.bind(getSelf(),
|
||||
new InetSocketAddress("localhost", 0), 100), getSelf());
|
||||
tcp.tell(TcpMessage.bind(self(),
|
||||
new InetSocketAddress("localhost", 0), 100), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof Bound) {
|
||||
manager.tell(msg, getSelf());
|
||||
|
||||
} else if (msg instanceof CommandFailed) {
|
||||
getContext().stop(getSelf());
|
||||
|
||||
} else if (msg instanceof Connected) {
|
||||
final Connected conn = (Connected) msg;
|
||||
manager.tell(conn, getSelf());
|
||||
final ActorRef handler = getContext().actorOf(
|
||||
Props.create(SimplisticHandler.class));
|
||||
getSender().tell(TcpMessage.register(handler), getSelf());
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Bound.class, msg -> {
|
||||
manager.tell(msg, self());
|
||||
|
||||
})
|
||||
.match(CommandFailed.class, msg -> {
|
||||
getContext().stop(self());
|
||||
|
||||
})
|
||||
.match(Connected.class, conn -> {
|
||||
manager.tell(conn, self());
|
||||
final ActorRef handler = getContext().actorOf(
|
||||
Props.create(SimplisticHandler.class));
|
||||
sender().tell(TcpMessage.register(handler), self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -75,23 +78,26 @@ public class IODocTest extends AbstractJavaTest {
|
|||
|
||||
static
|
||||
//#simplistic-handler
|
||||
public class SimplisticHandler extends UntypedActor {
|
||||
public class SimplisticHandler extends AbstractActor {
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof Received) {
|
||||
final ByteString data = ((Received) msg).data();
|
||||
System.out.println(data);
|
||||
getSender().tell(TcpMessage.write(data), getSelf());
|
||||
} else if (msg instanceof ConnectionClosed) {
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Received.class, msg -> {
|
||||
final ByteString data = msg.data();
|
||||
System.out.println(data);
|
||||
sender().tell(TcpMessage.write(data), self());
|
||||
})
|
||||
.match(ConnectionClosed.class, msg -> {
|
||||
getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#simplistic-handler
|
||||
|
||||
static
|
||||
//#client
|
||||
public class Client extends UntypedActor {
|
||||
public class Client extends AbstractActor {
|
||||
|
||||
final InetSocketAddress remote;
|
||||
final ActorRef listener;
|
||||
|
|
@ -105,44 +111,43 @@ public class IODocTest extends AbstractJavaTest {
|
|||
this.listener = listener;
|
||||
|
||||
final ActorRef tcp = Tcp.get(getContext().system()).manager();
|
||||
tcp.tell(TcpMessage.connect(remote), getSelf());
|
||||
tcp.tell(TcpMessage.connect(remote), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof CommandFailed) {
|
||||
listener.tell("failed", getSelf());
|
||||
getContext().stop(getSelf());
|
||||
|
||||
} else if (msg instanceof Connected) {
|
||||
listener.tell(msg, getSelf());
|
||||
getSender().tell(TcpMessage.register(getSelf()), getSelf());
|
||||
getContext().become(connected(getSender()));
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(CommandFailed.class, msg -> {
|
||||
listener.tell("failed", self());
|
||||
getContext().stop(self());
|
||||
|
||||
})
|
||||
.match(Connected.class, msg -> {
|
||||
listener.tell(msg, self());
|
||||
sender().tell(TcpMessage.register(self()), self());
|
||||
getContext().become(connected(sender()));
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private Procedure<Object> connected(final ActorRef connection) {
|
||||
return new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object msg) throws Exception {
|
||||
|
||||
if (msg instanceof ByteString) {
|
||||
connection.tell(TcpMessage.write((ByteString) msg), getSelf());
|
||||
|
||||
} else if (msg instanceof CommandFailed) {
|
||||
// OS kernel socket buffer was full
|
||||
|
||||
} else if (msg instanceof Received) {
|
||||
listener.tell(((Received) msg).data(), getSelf());
|
||||
|
||||
} else if (msg.equals("close")) {
|
||||
connection.tell(TcpMessage.close(), getSelf());
|
||||
|
||||
} else if (msg instanceof ConnectionClosed) {
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
};
|
||||
private Receive connected(final ActorRef connection) {
|
||||
return receiveBuilder()
|
||||
.match(ByteString.class, msg -> {
|
||||
connection.tell(TcpMessage.write((ByteString) msg), self());
|
||||
})
|
||||
.match(CommandFailed.class, msg -> {
|
||||
// OS kernel socket buffer was full
|
||||
})
|
||||
.match(Received.class, msg -> {
|
||||
listener.tell(msg.data(), self());
|
||||
})
|
||||
.matchEquals("close", msg -> {
|
||||
connection.tell(TcpMessage.close(), self());
|
||||
})
|
||||
.match(ConnectionClosed.class, msg -> {
|
||||
getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.LinkedList;
|
|||
import java.util.Queue;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.io.Tcp.ConnectionClosed;
|
||||
|
|
@ -20,10 +20,10 @@ import akka.japi.Procedure;
|
|||
import akka.util.ByteString;
|
||||
|
||||
//#simple-echo-handler
|
||||
public class SimpleEchoHandler extends UntypedActor {
|
||||
public class SimpleEchoHandler extends AbstractActor {
|
||||
|
||||
final LoggingAdapter log = Logging
|
||||
.getLogger(getContext().system(), getSelf());
|
||||
.getLogger(getContext().system(), self());
|
||||
|
||||
final ActorRef connection;
|
||||
final InetSocketAddress remote;
|
||||
|
|
@ -41,38 +41,42 @@ public class SimpleEchoHandler extends UntypedActor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof Received) {
|
||||
final ByteString data = ((Received) msg).data();
|
||||
buffer(data);
|
||||
connection.tell(TcpMessage.write(data, ACK), getSelf());
|
||||
// now switch behavior to “waiting for acknowledgement”
|
||||
getContext().become(buffering, false);
|
||||
|
||||
} else if (msg instanceof ConnectionClosed) {
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Received.class, msg -> {
|
||||
final ByteString data = msg.data();
|
||||
buffer(data);
|
||||
connection.tell(TcpMessage.write(data, ACK), self());
|
||||
// now switch behavior to “waiting for acknowledgement”
|
||||
getContext().become(buffering(), false);
|
||||
|
||||
})
|
||||
.match(ConnectionClosed.class, msg -> {
|
||||
getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private final Procedure<Object> buffering = new Procedure<Object>() {
|
||||
@Override
|
||||
public void apply(Object msg) throws Exception {
|
||||
if (msg instanceof Received) {
|
||||
buffer(((Received) msg).data());
|
||||
private final Receive buffering() {
|
||||
return receiveBuilder()
|
||||
.match(Received.class, msg -> {
|
||||
buffer(msg.data());
|
||||
|
||||
} else if (msg == ACK) {
|
||||
})
|
||||
.match(Event.class, msg -> msg == ACK, msg -> {
|
||||
acknowledge();
|
||||
|
||||
} else if (msg instanceof ConnectionClosed) {
|
||||
if (((ConnectionClosed) msg).isPeerClosed()) {
|
||||
})
|
||||
.match(ConnectionClosed.class, msg -> {
|
||||
if (msg.isPeerClosed()) {
|
||||
closing = true;
|
||||
} else {
|
||||
// could also be ErrorClosed, in which case we just give up
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
//#storage-omitted
|
||||
public void postStop() {
|
||||
|
|
@ -95,11 +99,11 @@ public class SimpleEchoHandler extends UntypedActor {
|
|||
|
||||
if (stored > maxStored) {
|
||||
log.warning("drop connection to [{}] (buffer overrun)", remote);
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
|
||||
} else if (stored > highWatermark) {
|
||||
log.debug("suspending reading");
|
||||
connection.tell(TcpMessage.suspendReading(), getSelf());
|
||||
connection.tell(TcpMessage.suspendReading(), self());
|
||||
suspended = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -111,18 +115,18 @@ public class SimpleEchoHandler extends UntypedActor {
|
|||
|
||||
if (suspended && stored < lowWatermark) {
|
||||
log.debug("resuming reading");
|
||||
connection.tell(TcpMessage.resumeReading(), getSelf());
|
||||
connection.tell(TcpMessage.resumeReading(), self());
|
||||
suspended = false;
|
||||
}
|
||||
|
||||
if (storage.isEmpty()) {
|
||||
if (closing) {
|
||||
getContext().stop(getSelf());
|
||||
getContext().stop(self());
|
||||
} else {
|
||||
getContext().unbecome();
|
||||
}
|
||||
} else {
|
||||
connection.tell(TcpMessage.write(storage.peek(), ACK), getSelf());
|
||||
connection.tell(TcpMessage.write(storage.peek(), ACK), self());
|
||||
}
|
||||
}
|
||||
//#simple-helpers
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import java.util.concurrent.CountDownLatch;
|
|||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Terminated;
|
||||
import akka.actor.UntypedActor;
|
||||
import akka.actor.AbstractActor;
|
||||
|
||||
public class Watcher extends UntypedActor {
|
||||
public class Watcher extends AbstractActor {
|
||||
|
||||
static public class Watch {
|
||||
final ActorRef target;
|
||||
|
|
@ -22,13 +22,16 @@ public class Watcher extends UntypedActor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object msg) throws Exception {
|
||||
if (msg instanceof Watch) {
|
||||
getContext().watch(((Watch) msg).target);
|
||||
} else if (msg instanceof Terminated) {
|
||||
latch.countDown();
|
||||
if (latch.getCount() == 0) getContext().stop(getSelf());
|
||||
}
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Watch.class, msg -> {
|
||||
getContext().watch(msg.target);
|
||||
})
|
||||
.match(Terminated.class, msg -> {
|
||||
latch.countDown();
|
||||
if (latch.getCount() == 0) getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class ConsistentHashingRouterDocTest extends AbstractJavaTest {
|
|||
} else if (msg instanceof Get) {
|
||||
Get get = (Get) msg;
|
||||
Object value = cache.get(get.key);
|
||||
getSender().tell(value == null ? NOT_FOUND : value,
|
||||
sender().tell(value == null ? NOT_FOUND : value,
|
||||
getContext().self());
|
||||
} else if (msg instanceof Evict) {
|
||||
Evict evict = (Evict) msg;
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public class CustomRouterDocTest extends AbstractJavaTest {
|
|||
|
||||
static public class Storage extends UntypedActor {
|
||||
public void onReceive(Object msg) {
|
||||
getSender().tell(msg, getSelf());
|
||||
sender().tell(msg, self());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public class RouterDocTest extends AbstractJavaTest {
|
|||
|
||||
public void onReceive(Object msg) {
|
||||
if (msg instanceof Work) {
|
||||
router.route(msg, getSender());
|
||||
router.route(msg, sender());
|
||||
} else if (msg instanceof Terminated) {
|
||||
router = router.removeRoutee(((Terminated) msg).actor());
|
||||
ActorRef r = getContext().actorOf(Props.create(Worker.class));
|
||||
|
|
@ -123,18 +123,18 @@ public class RouterDocTest extends AbstractJavaTest {
|
|||
|
||||
static public class Echo extends UntypedActor {
|
||||
public void onReceive(Object msg) {
|
||||
getSender().tell(msg, getSelf());
|
||||
sender().tell(msg, self());
|
||||
}
|
||||
}
|
||||
|
||||
static public class Replier extends UntypedActor {
|
||||
public void onReceive(Object msg) {
|
||||
//#reply-with-self
|
||||
getSender().tell("reply", getSelf());
|
||||
sender().tell("reply", self());
|
||||
//#reply-with-self
|
||||
|
||||
//#reply-with-parent
|
||||
getSender().tell("reply", getContext().parent());
|
||||
sender().tell("reply", getContext().parent());
|
||||
//#reply-with-parent
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class SchedulerPatternTest extends AbstractJavaTest {
|
|||
private final Cancellable tick = getContext().system().scheduler().schedule(
|
||||
Duration.create(500, TimeUnit.MILLISECONDS),
|
||||
Duration.create(1, TimeUnit.SECONDS),
|
||||
getSelf(), "tick", getContext().dispatcher(), null);
|
||||
self(), "tick", getContext().dispatcher(), null);
|
||||
//#schedule-constructor
|
||||
// this variable and constructor is declared here to not show up in the docs
|
||||
final ActorRef target;
|
||||
|
|
@ -49,7 +49,7 @@ public class SchedulerPatternTest extends AbstractJavaTest {
|
|||
if (message.equals("tick")) {
|
||||
// do something useful here
|
||||
//#schedule-constructor
|
||||
target.tell(message, getSelf());
|
||||
target.tell(message, self());
|
||||
//#schedule-constructor
|
||||
}
|
||||
//#schedule-constructor
|
||||
|
|
@ -79,7 +79,7 @@ public class SchedulerPatternTest extends AbstractJavaTest {
|
|||
public void preStart() {
|
||||
getContext().system().scheduler().scheduleOnce(
|
||||
Duration.create(500, TimeUnit.MILLISECONDS),
|
||||
getSelf(), "tick", getContext().dispatcher(), null);
|
||||
self(), "tick", getContext().dispatcher(), null);
|
||||
}
|
||||
|
||||
// override postRestart so we don't call preStart and schedule a new message
|
||||
|
|
@ -93,10 +93,10 @@ public class SchedulerPatternTest extends AbstractJavaTest {
|
|||
// send another periodic tick after the specified delay
|
||||
getContext().system().scheduler().scheduleOnce(
|
||||
Duration.create(1, TimeUnit.SECONDS),
|
||||
getSelf(), "tick", getContext().dispatcher(), null);
|
||||
self(), "tick", getContext().dispatcher(), null);
|
||||
// do something useful here
|
||||
//#schedule-receive
|
||||
target.tell(message, getSelf());
|
||||
target.tell(message, self());
|
||||
//#schedule-receive
|
||||
}
|
||||
//#schedule-receive
|
||||
|
|
|
|||
|
|
@ -74,13 +74,13 @@ public class SupervisedAsk {
|
|||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof AskParam) {
|
||||
askParam = (AskParam) message;
|
||||
caller = getSender();
|
||||
caller = sender();
|
||||
targetActor = getContext().actorOf(askParam.props);
|
||||
getContext().watch(targetActor);
|
||||
targetActor.forward(askParam.message, getContext());
|
||||
Scheduler scheduler = getContext().system().scheduler();
|
||||
timeoutMessage = scheduler.scheduleOnce(askParam.timeout.duration(),
|
||||
self(), new AskTimeout(), context().dispatcher(), null);
|
||||
self(), new AskTimeout(), getContext().dispatcher(), null);
|
||||
} else if (message instanceof Terminated) {
|
||||
Throwable ex = new ActorKilledException("Target actor terminated.");
|
||||
caller.tell(new Status.Failure(ex), self());
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import akka.pattern.BackoffSupervisor;
|
|||
import akka.persistence.*;
|
||||
import akka.persistence.journal.EventAdapter;
|
||||
import akka.persistence.journal.EventSeq;
|
||||
import scala.Option;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LambdaPersistenceDocTest {
|
||||
|
|
@ -42,7 +42,7 @@ public class LambdaPersistenceDocTest {
|
|||
|
||||
//#recover-on-restart-disabled
|
||||
@Override
|
||||
public void preRestart(Throwable reason, Option<Object> message) {}
|
||||
public void preRestart(Throwable reason, Optional<Object> message) {}
|
||||
//#recover-on-restart-disabled
|
||||
}
|
||||
|
||||
|
|
@ -65,14 +65,14 @@ public class LambdaPersistenceDocTest {
|
|||
//#persistence-id-override
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, cmd -> {/* ... */}).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(String.class, evt -> {/* ... */}).build();
|
||||
}
|
||||
|
||||
|
|
@ -85,8 +85,8 @@ public class LambdaPersistenceDocTest {
|
|||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(RecoveryCompleted.class, r -> {
|
||||
// perform init after recovery, before any other messages
|
||||
// ...
|
||||
|
|
@ -94,8 +94,8 @@ public class LambdaPersistenceDocTest {
|
|||
match(String.class, this::handleEvent).build();
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, s -> s.equals("cmd"),
|
||||
s -> persist("evt", this::handleEvent)).build();
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ public class LambdaPersistenceDocTest {
|
|||
Duration.create(3, TimeUnit.SECONDS),
|
||||
Duration.create(30, TimeUnit.SECONDS),
|
||||
0.2);
|
||||
context().actorOf(props, "mySupervisor");
|
||||
getContext().actorOf(props, "mySupervisor");
|
||||
super.preStart();
|
||||
}
|
||||
//#backoff
|
||||
|
|
@ -188,8 +188,8 @@ public class LambdaPersistenceDocTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, s -> {
|
||||
persist(new MsgSent(s), evt -> updateState(evt));
|
||||
}).
|
||||
|
|
@ -200,8 +200,8 @@ public class LambdaPersistenceDocTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(Object.class, evt -> updateState(evt)).build();
|
||||
}
|
||||
|
||||
|
|
@ -217,13 +217,14 @@ public class LambdaPersistenceDocTest {
|
|||
}
|
||||
|
||||
class MyDestination extends AbstractActor {
|
||||
public MyDestination() {
|
||||
receive(ReceiveBuilder.
|
||||
match(Msg.class, msg -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Msg.class, msg -> {
|
||||
// ...
|
||||
sender().tell(new Confirm(msg.deliveryId), self());
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#at-least-once-example
|
||||
|
|
@ -236,8 +237,8 @@ public class LambdaPersistenceDocTest {
|
|||
//#save-snapshot
|
||||
private Object state;
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, s -> s.equals("snap"),
|
||||
s -> saveSnapshot(state)).
|
||||
match(SaveSnapshotSuccess.class, ss -> {
|
||||
|
|
@ -255,8 +256,8 @@ public class LambdaPersistenceDocTest {
|
|||
return "persistence-id";
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(RecoveryCompleted.class, r -> {/* ...*/}).build();
|
||||
}
|
||||
|
||||
|
|
@ -279,8 +280,8 @@ public class LambdaPersistenceDocTest {
|
|||
//#snapshot-offer
|
||||
private Object state;
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(SnapshotOffer.class, s -> {
|
||||
state = s.snapshot();
|
||||
// ...
|
||||
|
|
@ -293,21 +294,22 @@ public class LambdaPersistenceDocTest {
|
|||
return "persistence-id";
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, s -> {/* ...*/}).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MyActor extends AbstractActor {
|
||||
ActorRef persistentActor;
|
||||
private final ActorRef persistentActor =
|
||||
getContext().actorOf(Props.create(MyPersistentActor.class));
|
||||
|
||||
public MyActor() {
|
||||
persistentActor = context().actorOf(Props.create(MyPersistentActor.class));
|
||||
receive(ReceiveBuilder.
|
||||
match(Object.class, o -> {/* ... */}).build()
|
||||
);
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Object.class, o -> {/* ... */})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -331,13 +333,13 @@ public class LambdaPersistenceDocTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(String.class, this::handleCommand).build();
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, this::handleCommand).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -383,13 +385,13 @@ public class LambdaPersistenceDocTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceiveRecover() {
|
||||
return receiveBuilder().
|
||||
match(String.class, this::handleCommand).build();
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.
|
||||
@Override public Receive createReceive() {
|
||||
return receiveBuilder().
|
||||
match(String.class, this::handleCommand).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -424,15 +426,15 @@ public class LambdaPersistenceDocTest {
|
|||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.matchAny(event -> {}).build();
|
||||
@Override public Receive createReceive() {
|
||||
return receiveBuilder().matchAny(event -> {}).build();
|
||||
}
|
||||
|
||||
//#nested-persist-persist
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
@Override public Receive createReceiveRecover() {
|
||||
final Procedure<String> replyToSender = event -> sender().tell(event, self());
|
||||
|
||||
return ReceiveBuilder
|
||||
return receiveBuilder()
|
||||
.match(String.class, msg -> {
|
||||
persist(String.format("%s-outer-1", msg), event -> {
|
||||
sender().tell(event, self());
|
||||
|
|
@ -477,15 +479,17 @@ public class LambdaPersistenceDocTest {
|
|||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder.matchAny(event -> {}).build();
|
||||
@Override
|
||||
public Receive createReceiveRecover() {
|
||||
return receiveBuilder().matchAny(event -> {}).build();
|
||||
}
|
||||
|
||||
//#nested-persistAsync-persistAsync
|
||||
@Override public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
final Procedure<String> replyToSender = event -> sender().tell(event, self());
|
||||
|
||||
return ReceiveBuilder
|
||||
return receiveBuilder()
|
||||
.match(String.class, msg -> {
|
||||
persistAsync(String.format("%s-outer-1", msg ), event -> {
|
||||
sender().tell(event, self());
|
||||
|
|
@ -539,10 +543,10 @@ public class LambdaPersistenceDocTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receiveCommand() {
|
||||
return ReceiveBuilder
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Shutdown.class, shutdown -> {
|
||||
context().stop(self());
|
||||
getContext().stop(self());
|
||||
})
|
||||
.match(String.class, msg -> {
|
||||
System.out.println(msg);
|
||||
|
|
@ -552,8 +556,8 @@ public class LambdaPersistenceDocTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receiveRecover() {
|
||||
return ReceiveBuilder.matchAny(any -> {}).build();
|
||||
public Receive createReceiveRecover() {
|
||||
return receiveBuilder().matchAny(any -> {}).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,12 +14,20 @@ import akka.persistence.snapshot.japi.*;
|
|||
import akka.actor.*;
|
||||
import akka.persistence.journal.leveldb.SharedLeveldbJournal;
|
||||
import akka.persistence.journal.leveldb.SharedLeveldbStore;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import scala.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
import org.iq80.leveldb.util.FileUtils;
|
||||
import java.util.Optional;
|
||||
|
||||
import akka.persistence.japi.journal.JavaJournalSpec;
|
||||
import akka.persistence.japi.snapshot.JavaSnapshotStoreSpec;
|
||||
|
||||
|
||||
public class LambdaPersistencePluginDocTest {
|
||||
|
||||
|
|
@ -35,21 +43,24 @@ public class LambdaPersistencePluginDocTest {
|
|||
@Override
|
||||
public void preStart() throws Exception {
|
||||
String path = "akka.tcp://example@127.0.0.1:2552/user/store";
|
||||
ActorSelection selection = context().actorSelection(path);
|
||||
ActorSelection selection = getContext().actorSelection(path);
|
||||
selection.tell(new Identify(1), self());
|
||||
}
|
||||
|
||||
public SharedStorageUsage() {
|
||||
receive(ReceiveBuilder.
|
||||
match(ActorIdentity.class, ai -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(ActorIdentity.class, ai -> {
|
||||
if (ai.correlationId().equals(1)) {
|
||||
ActorRef store = ai.getRef();
|
||||
if (store != null) {
|
||||
SharedLeveldbJournal.setStore(store, context().system());
|
||||
Optional<ActorRef> store = ai.getActorRef();
|
||||
if (store.isPresent()) {
|
||||
SharedLeveldbJournal.setStore(store.get(), getContext().system());
|
||||
} else {
|
||||
throw new RuntimeException("Couldn't identify store");
|
||||
}
|
||||
}
|
||||
}).build()
|
||||
);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#shared-store-usage
|
||||
|
|
@ -111,4 +122,79 @@ public class LambdaPersistencePluginDocTest {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Object o2 = new Object() {
|
||||
//#journal-tck-java
|
||||
class MyJournalSpecTest extends JavaJournalSpec {
|
||||
|
||||
public MyJournalSpecTest() {
|
||||
super(ConfigFactory.parseString(
|
||||
"persistence.journal.plugin = " +
|
||||
"\"akka.persistence.journal.leveldb-shared\""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityFlag supportsRejectingNonSerializableObjects() {
|
||||
return CapabilityFlag.off();
|
||||
}
|
||||
}
|
||||
//#journal-tck-java
|
||||
};
|
||||
|
||||
static Object o3 = new Object() {
|
||||
//#snapshot-store-tck-java
|
||||
class MySnapshotStoreTest extends JavaSnapshotStoreSpec {
|
||||
|
||||
public MySnapshotStoreTest() {
|
||||
super(ConfigFactory.parseString(
|
||||
"akka.persistence.snapshot-store.plugin = " +
|
||||
"\"akka.persistence.snapshot-store.local\""));
|
||||
}
|
||||
}
|
||||
//#snapshot-store-tck-java
|
||||
};
|
||||
|
||||
static Object o4 = new Object() {
|
||||
//#journal-tck-before-after-java
|
||||
class MyJournalSpecTest extends JavaJournalSpec {
|
||||
|
||||
List<File> storageLocations = new ArrayList<File>();
|
||||
|
||||
public MyJournalSpecTest() {
|
||||
super(ConfigFactory.parseString(
|
||||
"persistence.journal.plugin = " +
|
||||
"\"akka.persistence.journal.leveldb-shared\""));
|
||||
|
||||
Config config = system().settings().config();
|
||||
storageLocations.add(new File(
|
||||
config.getString("akka.persistence.journal.leveldb.dir")));
|
||||
storageLocations.add(new File(
|
||||
config.getString("akka.persistence.snapshot-store.local.dir")));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CapabilityFlag supportsRejectingNonSerializableObjects() {
|
||||
return CapabilityFlag.on();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeAll() {
|
||||
for (File storageLocation : storageLocations) {
|
||||
FileUtils.deleteRecursively(storageLocation);
|
||||
}
|
||||
super.beforeAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll() {
|
||||
super.afterAll();
|
||||
for (File storageLocation : storageLocations) {
|
||||
FileUtils.deleteRecursively(storageLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#journal-tck-before-after-java
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,584 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.persistence;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.pattern.BackoffSupervisor;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import akka.japi.Function;
|
||||
import akka.japi.Procedure;
|
||||
import akka.persistence.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class PersistenceDocTest {
|
||||
|
||||
public interface SomeOtherMessage {}
|
||||
|
||||
public interface PersistentActorMethods {
|
||||
//#persistence-id
|
||||
public String persistenceId();
|
||||
//#persistence-id
|
||||
//#recovery-status
|
||||
public boolean recoveryRunning();
|
||||
public boolean recoveryFinished();
|
||||
//#recovery-status
|
||||
}
|
||||
|
||||
static Object o2 = new Object() {
|
||||
abstract class MyPersistentActor1 extends UntypedPersistentActor {
|
||||
//#recovery-disabled
|
||||
@Override
|
||||
public Recovery recovery() {
|
||||
return Recovery.none();
|
||||
}
|
||||
//#recovery-disabled
|
||||
}
|
||||
|
||||
abstract class MyPersistentActor2 extends UntypedPersistentActor {
|
||||
//#recovery-custom
|
||||
@Override
|
||||
public Recovery recovery() {
|
||||
return Recovery.create(457L);
|
||||
}
|
||||
//#recovery-custom
|
||||
}
|
||||
|
||||
class MyPersistentActor4 extends UntypedPersistentActor implements PersistentActorMethods {
|
||||
//#persistence-id-override
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "my-stable-persistence-id";
|
||||
}
|
||||
//#persistence-id-override
|
||||
@Override
|
||||
public void onReceiveRecover(Object message) throws Exception {}
|
||||
@Override
|
||||
public void onReceiveCommand(Object message) throws Exception {}
|
||||
}
|
||||
|
||||
class MyPersistentActor5 extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "persistence-id";
|
||||
}
|
||||
|
||||
//#recovery-completed
|
||||
@Override
|
||||
public void onReceiveRecover(Object message) {
|
||||
if (message instanceof RecoveryCompleted) {
|
||||
// perform init after recovery, before any other messages
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object message) throws Exception {
|
||||
if (message instanceof String) {
|
||||
// ...
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
//#recovery-completed
|
||||
}
|
||||
|
||||
abstract class MyPersistentActor6 extends UntypedPersistentActor {
|
||||
//#recovery-no-snap
|
||||
@Override
|
||||
public Recovery recovery() {
|
||||
return Recovery.create(SnapshotSelectionCriteria.none());
|
||||
}
|
||||
//#recovery-no-snap
|
||||
}
|
||||
|
||||
abstract class MyActor extends UntypedPersistentActor {
|
||||
//#backoff
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
final Props childProps = Props.create(MyPersistentActor1.class);
|
||||
final Props props = BackoffSupervisor.props(
|
||||
childProps,
|
||||
"myActor",
|
||||
Duration.create(3, TimeUnit.SECONDS),
|
||||
Duration.create(30, TimeUnit.SECONDS),
|
||||
0.2);
|
||||
getContext().actorOf(props, "mySupervisor");
|
||||
super.preStart();
|
||||
}
|
||||
//#backoff
|
||||
}
|
||||
};
|
||||
|
||||
static Object atLeastOnceExample = new Object() {
|
||||
//#at-least-once-example
|
||||
|
||||
class Msg implements Serializable {
|
||||
public final long deliveryId;
|
||||
public final String s;
|
||||
|
||||
public Msg(long deliveryId, String s) {
|
||||
this.deliveryId = deliveryId;
|
||||
this.s = s;
|
||||
}
|
||||
}
|
||||
|
||||
class Confirm implements Serializable {
|
||||
public final long deliveryId;
|
||||
|
||||
public Confirm(long deliveryId) {
|
||||
this.deliveryId = deliveryId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MsgSent implements Serializable {
|
||||
public final String s;
|
||||
|
||||
public MsgSent(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
}
|
||||
class MsgConfirmed implements Serializable {
|
||||
public final long deliveryId;
|
||||
|
||||
public MsgConfirmed(long deliveryId) {
|
||||
this.deliveryId = deliveryId;
|
||||
}
|
||||
}
|
||||
|
||||
class MyPersistentActor extends UntypedPersistentActorWithAtLeastOnceDelivery {
|
||||
private final ActorSelection destination;
|
||||
|
||||
@Override
|
||||
public String persistenceId() { return "persistence-id"; }
|
||||
|
||||
public MyPersistentActor(ActorSelection destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object message) {
|
||||
if (message instanceof String) {
|
||||
String s = (String) message;
|
||||
persist(new MsgSent(s), new Procedure<MsgSent>() {
|
||||
public void apply(MsgSent evt) {
|
||||
updateState(evt);
|
||||
}
|
||||
});
|
||||
} else if (message instanceof Confirm) {
|
||||
Confirm confirm = (Confirm) message;
|
||||
persist(new MsgConfirmed(confirm.deliveryId), new Procedure<MsgConfirmed>() {
|
||||
public void apply(MsgConfirmed evt) {
|
||||
updateState(evt);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object event) {
|
||||
updateState(event);
|
||||
}
|
||||
|
||||
void updateState(Object event) {
|
||||
if (event instanceof MsgSent) {
|
||||
final MsgSent evt = (MsgSent) event;
|
||||
deliver(destination, new Function<Long, Object>() {
|
||||
public Object apply(Long deliveryId) {
|
||||
return new Msg(deliveryId, evt.s);
|
||||
}
|
||||
});
|
||||
} else if (event instanceof MsgConfirmed) {
|
||||
final MsgConfirmed evt = (MsgConfirmed) event;
|
||||
confirmDelivery(evt.deliveryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyDestination extends UntypedActor {
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof Msg) {
|
||||
Msg msg = (Msg) message;
|
||||
// ...
|
||||
getSender().tell(new Confirm(msg.deliveryId), getSelf());
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#at-least-once-example
|
||||
};
|
||||
|
||||
static Object o4 = new Object() {
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() { return "persistence-id"; }
|
||||
|
||||
//#save-snapshot
|
||||
private Object state;
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object message) {
|
||||
if (message.equals("snap")) {
|
||||
saveSnapshot(state);
|
||||
} else if (message instanceof SaveSnapshotSuccess) {
|
||||
SnapshotMetadata metadata = ((SaveSnapshotSuccess)message).metadata();
|
||||
// ...
|
||||
} else if (message instanceof SaveSnapshotFailure) {
|
||||
SnapshotMetadata metadata = ((SaveSnapshotFailure)message).metadata();
|
||||
// ...
|
||||
}
|
||||
}
|
||||
//#save-snapshot
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object event) {
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static Object o5 = new Object() {
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
|
||||
//#snapshot-criteria
|
||||
@Override
|
||||
public Recovery recovery() {
|
||||
return Recovery.create(
|
||||
SnapshotSelectionCriteria
|
||||
.create(457L, System.currentTimeMillis()));
|
||||
}
|
||||
//#snapshot-criteria
|
||||
|
||||
@Override
|
||||
public String persistenceId() { return "persistence-id"; }
|
||||
|
||||
//#snapshot-offer
|
||||
private Object state;
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object message) {
|
||||
if (message instanceof SnapshotOffer) {
|
||||
state = ((SnapshotOffer)message).snapshot();
|
||||
// ...
|
||||
} else if (message instanceof RecoveryCompleted) {
|
||||
// ...
|
||||
} else {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
//#snapshot-offer
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object message) {
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static Object o9 = new Object() {
|
||||
//#persist-async
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() { return "some-persistence-id"; }
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) {
|
||||
// handle recovery here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
sender().tell(msg, self());
|
||||
|
||||
persistAsync(String.format("evt-%s-1", msg), new Procedure<String>(){
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
});
|
||||
persistAsync(String.format("evt-%s-2", msg), new Procedure<String>(){
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//#persist-async
|
||||
|
||||
public void usage() {
|
||||
final ActorSystem system = ActorSystem.create("example");
|
||||
//#persist-async-usage
|
||||
final ActorRef persistentActor = system.actorOf(Props.create(MyPersistentActor.class));
|
||||
persistentActor.tell("a", null);
|
||||
persistentActor.tell("b", null);
|
||||
|
||||
// possible order of received messages:
|
||||
// a
|
||||
// b
|
||||
// evt-a-1
|
||||
// evt-a-2
|
||||
// evt-b-1
|
||||
// evt-b-2
|
||||
//#persist-async-usage
|
||||
}
|
||||
};
|
||||
|
||||
static Object o10 = new Object() {
|
||||
//#defer
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() { return "some-persistence-id"; }
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) {
|
||||
// handle recovery here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
final Procedure<String> replyToSender = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
};
|
||||
|
||||
persistAsync(String.format("evt-%s-1", msg), replyToSender);
|
||||
persistAsync(String.format("evt-%s-2", msg), replyToSender);
|
||||
deferAsync(String.format("evt-%s-3", msg), replyToSender);
|
||||
}
|
||||
}
|
||||
//#defer
|
||||
|
||||
public void usage() {
|
||||
final ActorSystem system = ActorSystem.create("example");
|
||||
//#defer-caller
|
||||
final ActorRef persistentActor = system.actorOf(Props.create(MyPersistentActor.class));
|
||||
persistentActor.tell("a", null);
|
||||
persistentActor.tell("b", null);
|
||||
|
||||
// order of received messages:
|
||||
// a
|
||||
// b
|
||||
// evt-a-1
|
||||
// evt-a-2
|
||||
// evt-a-3
|
||||
// evt-b-1
|
||||
// evt-b-2
|
||||
// evt-b-3
|
||||
//#defer-caller
|
||||
}
|
||||
};
|
||||
|
||||
static Object o11 = new Object() {
|
||||
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) {
|
||||
// handle recovery here
|
||||
}
|
||||
|
||||
//#nested-persist-persist
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
final Procedure<String> replyToSender = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
};
|
||||
|
||||
final Procedure<String> outer1Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persist(String.format("%s-inner-1", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
final Procedure<String> outer2Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persist(String.format("%s-inner-2", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
|
||||
persist(String.format("%s-outer-1", msg), outer1Callback);
|
||||
persist(String.format("%s-outer-2", msg), outer2Callback);
|
||||
}
|
||||
//#nested-persist-persist
|
||||
|
||||
void usage(ActorRef persistentActor) {
|
||||
//#nested-persist-persist-caller
|
||||
persistentActor.tell("a", self());
|
||||
persistentActor.tell("b", self());
|
||||
|
||||
// order of received messages:
|
||||
// a
|
||||
// a-outer-1
|
||||
// a-outer-2
|
||||
// a-inner-1
|
||||
// a-inner-2
|
||||
// and only then process "b"
|
||||
// b
|
||||
// b-outer-1
|
||||
// b-outer-2
|
||||
// b-inner-1
|
||||
// b-inner-2
|
||||
|
||||
//#nested-persist-persist-caller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MyPersistAsyncActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) {
|
||||
// handle recovery here
|
||||
}
|
||||
|
||||
//#nested-persistAsync-persistAsync
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
final Procedure<String> replyToSender = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
};
|
||||
|
||||
final Procedure<String> outer1Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persistAsync(String.format("%s-inner-1", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
final Procedure<String> outer2Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persistAsync(String.format("%s-inner-1", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
|
||||
persistAsync(String.format("%s-outer-1", msg), outer1Callback);
|
||||
persistAsync(String.format("%s-outer-2", msg), outer2Callback);
|
||||
}
|
||||
//#nested-persistAsync-persistAsync
|
||||
|
||||
|
||||
void usage(ActorRef persistentActor) {
|
||||
//#nested-persistAsync-persistAsync-caller
|
||||
persistentActor.tell("a", ActorRef.noSender());
|
||||
persistentActor.tell("b", ActorRef.noSender());
|
||||
|
||||
// order of received messages:
|
||||
// a
|
||||
// b
|
||||
// a-outer-1
|
||||
// a-outer-2
|
||||
// b-outer-1
|
||||
// b-outer-2
|
||||
// a-inner-1
|
||||
// a-inner-2
|
||||
// b-inner-1
|
||||
// b-inner-2
|
||||
|
||||
// which can be seen as the following causal relationship:
|
||||
// a -> a-outer-1 -> a-outer-2 -> a-inner-1 -> a-inner-2
|
||||
// b -> b-outer-1 -> b-outer-2 -> b-inner-1 -> b-inner-2
|
||||
|
||||
//#nested-persistAsync-persistAsync-caller
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static Object o13 = new Object() {
|
||||
//#safe-shutdown
|
||||
final class Shutdown {}
|
||||
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "some-persistence-id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) throws Exception {
|
||||
if (msg instanceof Shutdown) {
|
||||
context().stop(self());
|
||||
} else if (msg instanceof String) {
|
||||
System.out.println(msg);
|
||||
persist("handle-" + msg, new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String param) throws Exception {
|
||||
System.out.println(param);
|
||||
}
|
||||
});
|
||||
} else unhandled(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) throws Exception {
|
||||
// handle recovery...
|
||||
}
|
||||
}
|
||||
//#safe-shutdown
|
||||
|
||||
|
||||
public void usage() {
|
||||
final ActorSystem system = ActorSystem.create("example");
|
||||
final ActorRef persistentActor = system.actorOf(Props.create(MyPersistentActor.class));
|
||||
//#safe-shutdown-example-bad
|
||||
// UN-SAFE, due to PersistentActor's command stashing:
|
||||
persistentActor.tell("a", ActorRef.noSender());
|
||||
persistentActor.tell("b", ActorRef.noSender());
|
||||
persistentActor.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
// order of received messages:
|
||||
// a
|
||||
// # b arrives at mailbox, stashing; internal-stash = [b]
|
||||
// # PoisonPill arrives at mailbox, stashing; internal-stash = [b, Shutdown]
|
||||
// PoisonPill is an AutoReceivedMessage, is handled automatically
|
||||
// !! stop !!
|
||||
// Actor is stopped without handling `b` nor the `a` handler!
|
||||
//#safe-shutdown-example-bad
|
||||
|
||||
//#safe-shutdown-example-good
|
||||
// SAFE:
|
||||
persistentActor.tell("a", ActorRef.noSender());
|
||||
persistentActor.tell("b", ActorRef.noSender());
|
||||
persistentActor.tell(new Shutdown(), ActorRef.noSender());
|
||||
// order of received messages:
|
||||
// a
|
||||
// # b arrives at mailbox, stashing; internal-stash = [b]
|
||||
// # Shutdown arrives at mailbox, stashing; internal-stash = [b, Shutdown]
|
||||
// handle-a
|
||||
// # unstashing; internal-stash = [Shutdown]
|
||||
// b
|
||||
// handle-b
|
||||
// # unstashing; internal-stash = []
|
||||
// Shutdown
|
||||
// -- stop --
|
||||
//#safe-shutdown-example-good
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package docs.persistence;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.dispatch.Futures;
|
||||
import akka.persistence.japi.journal.JavaJournalSpec;
|
||||
import akka.persistence.japi.snapshot.JavaSnapshotStoreSpec;
|
||||
import akka.persistence.journal.leveldb.SharedLeveldbJournal;
|
||||
import akka.persistence.journal.leveldb.SharedLeveldbStore;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import org.iq80.leveldb.util.FileUtils;
|
||||
import scala.concurrent.Future;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
//#plugin-imports
|
||||
import akka.persistence.*;
|
||||
import akka.persistence.journal.japi.AsyncWriteJournal;
|
||||
import akka.persistence.snapshot.japi.SnapshotStore;
|
||||
//#plugin-imports
|
||||
|
||||
public class PersistencePluginDocTest {
|
||||
|
||||
|
||||
static Object o1 = new Object() {
|
||||
final ActorSystem system = null;
|
||||
//#shared-store-creation
|
||||
final ActorRef store = system.actorOf(Props.create(SharedLeveldbStore.class), "store");
|
||||
//#shared-store-creation
|
||||
|
||||
//#shared-store-usage
|
||||
class SharedStorageUsage extends UntypedActor {
|
||||
@Override
|
||||
public void preStart() throws Exception {
|
||||
String path = "akka.tcp://example@127.0.0.1:2552/user/store";
|
||||
ActorSelection selection = getContext().actorSelection(path);
|
||||
selection.tell(new Identify(1), getSelf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) throws Exception {
|
||||
if (message instanceof ActorIdentity) {
|
||||
ActorIdentity identity = (ActorIdentity) message;
|
||||
if (identity.correlationId().equals(1)) {
|
||||
ActorRef store = identity.getRef();
|
||||
if (store != null) {
|
||||
SharedLeveldbJournal.setStore(store, getContext().system());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//#shared-store-usage
|
||||
};
|
||||
|
||||
class MySnapshotStore extends SnapshotStore {
|
||||
@Override
|
||||
public Future<Optional<SelectedSnapshot>> doLoadAsync(String persistenceId, SnapshotSelectionCriteria criteria) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> doSaveAsync(SnapshotMetadata metadata, Object snapshot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> doDeleteAsync(SnapshotMetadata metadata) {
|
||||
return Futures.successful(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> doDeleteAsync(String persistenceId, SnapshotSelectionCriteria criteria) {
|
||||
return Futures.successful(null);
|
||||
}
|
||||
}
|
||||
|
||||
class MyAsyncJournal extends AsyncWriteJournal {
|
||||
//#sync-journal-plugin-api
|
||||
@Override
|
||||
public Future<Iterable<Optional<Exception>>> doAsyncWriteMessages(
|
||||
Iterable<AtomicWrite> messages) {
|
||||
try {
|
||||
Iterable<Optional<Exception>> result = new ArrayList<Optional<Exception>>();
|
||||
// blocking call here...
|
||||
// result.add(..)
|
||||
return Futures.successful(result);
|
||||
} catch (Exception e) {
|
||||
return Futures.failed(e);
|
||||
}
|
||||
}
|
||||
//#sync-journal-plugin-api
|
||||
|
||||
@Override
|
||||
public Future<Void> doAsyncDeleteMessagesTo(String persistenceId, long toSequenceNr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> doAsyncReplayMessages(String persistenceId, long fromSequenceNr,
|
||||
long toSequenceNr, long max, Consumer<PersistentRepr> replayCallback) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Long> doAsyncReadHighestSequenceNr(String persistenceId, long fromSequenceNr) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Object o2 = new Object() {
|
||||
//#journal-tck-java
|
||||
class MyJournalSpecTest extends JavaJournalSpec {
|
||||
|
||||
public MyJournalSpecTest() {
|
||||
super(ConfigFactory.parseString(
|
||||
"persistence.journal.plugin = " +
|
||||
"\"akka.persistence.journal.leveldb-shared\""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityFlag supportsRejectingNonSerializableObjects() {
|
||||
return CapabilityFlag.off();
|
||||
}
|
||||
}
|
||||
//#journal-tck-java
|
||||
};
|
||||
|
||||
static Object o3 = new Object() {
|
||||
//#snapshot-store-tck-java
|
||||
class MySnapshotStoreTest extends JavaSnapshotStoreSpec {
|
||||
|
||||
public MySnapshotStoreTest() {
|
||||
super(ConfigFactory.parseString(
|
||||
"akka.persistence.snapshot-store.plugin = " +
|
||||
"\"akka.persistence.snapshot-store.local\""));
|
||||
}
|
||||
}
|
||||
//#snapshot-store-tck-java
|
||||
};
|
||||
|
||||
static Object o4 = new Object() {
|
||||
//#journal-tck-before-after-java
|
||||
class MyJournalSpecTest extends JavaJournalSpec {
|
||||
|
||||
List<File> storageLocations = new ArrayList<File>();
|
||||
|
||||
public MyJournalSpecTest() {
|
||||
super(ConfigFactory.parseString(
|
||||
"persistence.journal.plugin = " +
|
||||
"\"akka.persistence.journal.leveldb-shared\""));
|
||||
|
||||
Config config = system().settings().config();
|
||||
storageLocations.add(new File(
|
||||
config.getString("akka.persistence.journal.leveldb.dir")));
|
||||
storageLocations.add(new File(
|
||||
config.getString("akka.persistence.snapshot-store.local.dir")));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CapabilityFlag supportsRejectingNonSerializableObjects() {
|
||||
return CapabilityFlag.on();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeAll() {
|
||||
for (File storageLocation : storageLocations) {
|
||||
FileUtils.deleteRecursively(storageLocation);
|
||||
}
|
||||
super.beforeAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll() {
|
||||
super.afterAll();
|
||||
for (File storageLocation : storageLocations) {
|
||||
FileUtils.deleteRecursively(storageLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#journal-tck-before-after-java
|
||||
};
|
||||
}
|
||||
|
|
@ -451,15 +451,20 @@ public class PersistenceQueryDocTest {
|
|||
|
||||
public TheOneWhoWritesToQueryJournal() {
|
||||
store = new ExampleStore();
|
||||
|
||||
receive(ReceiveBuilder.matchAny(message -> {
|
||||
state = updateState(state, message);
|
||||
|
||||
// example saving logic that requires state to become ready:
|
||||
if (state.readyToSave())
|
||||
store.save(Record.of(state));
|
||||
|
||||
}).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchAny(message -> {
|
||||
state = updateState(state, message);
|
||||
|
||||
// example saving logic that requires state to become ready:
|
||||
if (state.readyToSave())
|
||||
store.save(Record.of(state));
|
||||
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import static java.util.stream.Collectors.toList;
|
|||
//#events-by-tag-publisher
|
||||
class MyEventsByTagJavaPublisher extends AbstractActorPublisher<EventEnvelope> {
|
||||
private final Serialization serialization =
|
||||
SerializationExtension.get(context().system());
|
||||
SerializationExtension.get(getContext().system());
|
||||
|
||||
private final Connection connection;
|
||||
|
||||
|
|
@ -54,20 +54,23 @@ class MyEventsByTagJavaPublisher extends AbstractActorPublisher<EventEnvelope> {
|
|||
this.tag = tag;
|
||||
this.currentOffset = offset;
|
||||
|
||||
final Scheduler scheduler = context().system().scheduler();
|
||||
final Scheduler scheduler = getContext().system().scheduler();
|
||||
this.continueTask = scheduler
|
||||
.schedule(refreshInterval, refreshInterval, self(), CONTINUE,
|
||||
context().dispatcher(), self());
|
||||
|
||||
receive(ReceiveBuilder
|
||||
.matchEquals(CONTINUE, (in) -> {
|
||||
query();
|
||||
deliverBuf();
|
||||
})
|
||||
.match(Cancel.class, (in) -> {
|
||||
context().stop(self());
|
||||
getContext().dispatcher(), self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals(CONTINUE, (in) -> {
|
||||
query();
|
||||
deliverBuf();
|
||||
})
|
||||
.build());
|
||||
.match(Cancel.class, (in) -> {
|
||||
getContext().stop(self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Props props(Connection conn, String tag, Long offset,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class RemoteDeploymentDocTest {
|
|||
|
||||
public static class SampleActor extends UntypedActor {
|
||||
public void onReceive(Object message) {
|
||||
getSender().tell(getSelf(), getSelf());
|
||||
sender().tell(self(), self());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public class ActorPublisherDocTest extends AbstractJavaTest {
|
|||
}
|
||||
public static final JobDeniedMessage JobDenied = new JobDeniedMessage();
|
||||
}
|
||||
|
||||
public static class JobManager extends AbstractActorPublisher<JobManagerProtocol.Job> {
|
||||
|
||||
public static Props props() { return Props.create(JobManager.class); }
|
||||
|
|
@ -74,12 +75,13 @@ public class ActorPublisherDocTest extends AbstractJavaTest {
|
|||
private final int MAX_BUFFER_SIZE = 100;
|
||||
private final List<JobManagerProtocol.Job> buf = new ArrayList<>();
|
||||
|
||||
public JobManager() {
|
||||
receive(ReceiveBuilder.
|
||||
match(JobManagerProtocol.Job.class, job -> buf.size() == MAX_BUFFER_SIZE, job -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(JobManagerProtocol.Job.class, job -> buf.size() == MAX_BUFFER_SIZE, job -> {
|
||||
sender().tell(JobManagerProtocol.JobDenied, self());
|
||||
}).
|
||||
match(JobManagerProtocol.Job.class, job -> {
|
||||
})
|
||||
.match(JobManagerProtocol.Job.class, job -> {
|
||||
sender().tell(JobManagerProtocol.JobAccepted, self());
|
||||
|
||||
if (buf.isEmpty() && totalDemand() > 0)
|
||||
|
|
@ -88,10 +90,10 @@ public class ActorPublisherDocTest extends AbstractJavaTest {
|
|||
buf.add(job);
|
||||
deliverBuf();
|
||||
}
|
||||
}).
|
||||
match(ActorPublisherMessage.Request.class, request -> deliverBuf()).
|
||||
match(ActorPublisherMessage.Cancel.class, cancel -> context().stop(self())).
|
||||
build());
|
||||
})
|
||||
.match(ActorPublisherMessage.Request.class, request -> deliverBuf())
|
||||
.match(ActorPublisherMessage.Cancel.class, cancel -> getContext().stop(self()))
|
||||
.build();
|
||||
}
|
||||
|
||||
void deliverBuf() {
|
||||
|
|
|
|||
|
|
@ -161,44 +161,49 @@ public class ActorSubscriberDocTest extends AbstractJavaTest {
|
|||
public WorkerPool() {
|
||||
final List<Routee> routees = new ArrayList<>();
|
||||
for (int i = 0; i < 3; i++)
|
||||
routees.add(new ActorRefRoutee(context().actorOf(Props.create(Worker.class))));
|
||||
routees.add(new ActorRefRoutee(getContext().actorOf(Props.create(Worker.class))));
|
||||
router = new Router(new RoundRobinRoutingLogic(), routees);
|
||||
|
||||
receive(ReceiveBuilder.
|
||||
match(ActorSubscriberMessage.OnNext.class, on -> on.element() instanceof WorkerPoolProtocol.Msg,
|
||||
onNext -> {
|
||||
WorkerPoolProtocol.Msg msg = (WorkerPoolProtocol.Msg) onNext.element();
|
||||
queue.put(msg.id, msg.replyTo);
|
||||
|
||||
if (queue.size() > MAX_QUEUE_SIZE)
|
||||
throw new RuntimeException("queued too many: " + queue.size());
|
||||
|
||||
router.route(WorkerPoolProtocol.work(msg.id), self());
|
||||
}).
|
||||
match(ActorSubscriberMessage.onCompleteInstance().getClass(), complete -> {
|
||||
if (queue.isEmpty()) {
|
||||
context().stop(self());
|
||||
}
|
||||
}).
|
||||
match(WorkerPoolProtocol.Reply.class, reply -> {
|
||||
int id = reply.id;
|
||||
queue.get(id).tell(WorkerPoolProtocol.done(id), self());
|
||||
queue.remove(id);
|
||||
if (canceled() && queue.isEmpty()) {
|
||||
context().stop(self());
|
||||
}
|
||||
}).
|
||||
build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(ActorSubscriberMessage.OnNext.class, on -> on.element() instanceof WorkerPoolProtocol.Msg,
|
||||
onNext -> {
|
||||
WorkerPoolProtocol.Msg msg = (WorkerPoolProtocol.Msg) onNext.element();
|
||||
queue.put(msg.id, msg.replyTo);
|
||||
|
||||
if (queue.size() > MAX_QUEUE_SIZE)
|
||||
throw new RuntimeException("queued too many: " + queue.size());
|
||||
|
||||
router.route(WorkerPoolProtocol.work(msg.id), self());
|
||||
})
|
||||
.match(ActorSubscriberMessage.onCompleteInstance().getClass(), complete -> {
|
||||
if (queue.isEmpty()) {
|
||||
getContext().stop(self());
|
||||
}
|
||||
})
|
||||
.match(WorkerPoolProtocol.Reply.class, reply -> {
|
||||
int id = reply.id;
|
||||
queue.get(id).tell(WorkerPoolProtocol.done(id), self());
|
||||
queue.remove(id);
|
||||
if (canceled() && queue.isEmpty()) {
|
||||
getContext().stop(self());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
static class Worker extends AbstractActor {
|
||||
public Worker() {
|
||||
receive(ReceiveBuilder.
|
||||
match(WorkerPoolProtocol.Work.class, work -> {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(WorkerPoolProtocol.Work.class, work -> {
|
||||
// ...
|
||||
sender().tell(WorkerPoolProtocol.reply(work.id), self());
|
||||
}).build());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
//#worker-pool
|
||||
|
|
|
|||
|
|
@ -255,13 +255,18 @@ public class IntegrationDocTest extends AbstractJavaTest {
|
|||
static class DatabaseService extends AbstractActor {
|
||||
public final ActorRef probe;
|
||||
|
||||
DatabaseService(ActorRef probe) {
|
||||
public DatabaseService(ActorRef probe) {
|
||||
this.probe = probe;
|
||||
|
||||
receive(ReceiveBuilder.match(Save.class, s -> {
|
||||
probe.tell(s.tweet.author.handle, ActorRef.noSender());
|
||||
sender().tell(SaveDone.INSTANCE, self());
|
||||
}).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(Save.class, s -> {
|
||||
probe.tell(s.tweet.author.handle, ActorRef.noSender());
|
||||
sender().tell(SaveDone.INSTANCE, self());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +303,7 @@ public class IntegrationDocTest extends AbstractJavaTest {
|
|||
// ... process message
|
||||
String reply = word.toUpperCase();
|
||||
// reply to the ask
|
||||
getSender().tell(reply, getSelf());
|
||||
sender().tell(reply, self());
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public class TwitterStreamQuickstartDocTest extends AbstractJavaTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("SampleActorTest");
|
||||
system = ActorSystem.create("TwitterStreamQuickstartDocTest");
|
||||
mat = ActorMaterializer.create(system);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,14 +87,17 @@ public class RecipeGlobalRateLimit extends RecipeTest {
|
|||
this.tokenRefreshPeriod,
|
||||
self(),
|
||||
REPLENISH_TOKENS,
|
||||
context().system().dispatcher(),
|
||||
getContext().system().dispatcher(),
|
||||
self());
|
||||
|
||||
receive(open());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return open();
|
||||
}
|
||||
|
||||
PartialFunction<Object, BoxedUnit> open() {
|
||||
return ReceiveBuilder
|
||||
private Receive open() {
|
||||
return receiveBuilder()
|
||||
.match(ReplenishTokens.class, rt -> {
|
||||
permitTokens = Math.min(permitTokens + tokenRefreshAmount, maxAvailableTokens);
|
||||
})
|
||||
|
|
@ -102,13 +105,14 @@ public class RecipeGlobalRateLimit extends RecipeTest {
|
|||
permitTokens -= 1;
|
||||
sender().tell(MAY_PASS, self());
|
||||
if (permitTokens == 0) {
|
||||
context().become(closed());
|
||||
getContext().become(closed());
|
||||
}
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
PartialFunction<Object, BoxedUnit> closed() {
|
||||
return ReceiveBuilder
|
||||
private Receive closed() {
|
||||
return receiveBuilder()
|
||||
.match(ReplenishTokens.class, rt -> {
|
||||
permitTokens = Math.min(permitTokens + tokenRefreshAmount, maxAvailableTokens);
|
||||
releaseWaiting();
|
||||
|
|
@ -128,7 +132,7 @@ public class RecipeGlobalRateLimit extends RecipeTest {
|
|||
permitTokens -= toBeReleased.size();
|
||||
toBeReleased.stream().forEach(ref -> ref.tell(MAY_PASS, self()));
|
||||
if (permitTokens > 0) {
|
||||
context().become(open());
|
||||
getContext().become(open());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class ParentChildTest {
|
|||
|
||||
//#test-example
|
||||
static class Parent extends UntypedActor {
|
||||
final ActorRef child = context().actorOf(Props.create(Child.class), "child");
|
||||
final ActorRef child = getContext().actorOf(Props.create(Child.class), "child");
|
||||
boolean ponged = false;
|
||||
|
||||
@Override public void onReceive(Object message) throws Exception {
|
||||
|
|
@ -45,7 +45,7 @@ public class ParentChildTest {
|
|||
static class Child extends UntypedActor {
|
||||
@Override public void onReceive(Object message) throws Exception {
|
||||
if ("ping".equals(message)) {
|
||||
context().parent().tell("pong", self());
|
||||
getContext().parent().tell("pong", self());
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ public class ParentChildTest {
|
|||
boolean ponged = false;
|
||||
|
||||
public DependentParent(Props childProps) {
|
||||
child = context().actorOf(childProps, "child");
|
||||
child = getContext().actorOf(childProps, "child");
|
||||
}
|
||||
|
||||
@Override public void onReceive(Object message) throws Exception {
|
||||
|
|
@ -102,7 +102,7 @@ public class ParentChildTest {
|
|||
|
||||
public GenericDependentParent(Function<ActorRefFactory, ActorRef> childMaker)
|
||||
throws Exception {
|
||||
child = childMaker.apply(context());
|
||||
child = childMaker.apply(getContext());
|
||||
}
|
||||
|
||||
@Override public void onReceive(Object message) throws Exception {
|
||||
|
|
@ -175,13 +175,13 @@ public class ParentChildTest {
|
|||
|
||||
@Override public Actor create() throws Exception {
|
||||
return new UntypedActor() {
|
||||
final ActorRef child = context().actorOf(Props.create(Child.class), "child");
|
||||
final ActorRef child = getContext().actorOf(Props.create(Child.class), "child");
|
||||
|
||||
@Override public void onReceive(Object x) throws Exception {
|
||||
if (sender().equals(child)) {
|
||||
proxy.ref().forward(x, context());
|
||||
proxy.ref().forward(x, getContext());
|
||||
} else {
|
||||
child.forward(x, context());
|
||||
child.forward(x, getContext());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class TestKitDocTest {
|
|||
static class MyActor extends UntypedActor {
|
||||
public void onReceive(Object o) throws Exception {
|
||||
if (o.equals("say42")) {
|
||||
getSender().tell(42, getSelf());
|
||||
sender().tell(42, self());
|
||||
} else if (o instanceof Exception) {
|
||||
throw (Exception) o;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ public class TestKitSampleTest {
|
|||
public void onReceive(Object msg) {
|
||||
|
||||
if (msg.equals("hello")) {
|
||||
getSender().tell("world", getSelf());
|
||||
sender().tell("world", self());
|
||||
if (target != null) target.forward(msg, getContext());
|
||||
|
||||
} else if (msg instanceof ActorRef) {
|
||||
target = (ActorRef) msg;
|
||||
getSender().tell("done", getSelf());
|
||||
sender().tell("done", self());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue