diff --git a/akka-docs/rst/java/code/docs/pattern/JavaAsk.java b/akka-docs/rst/java/code/docs/pattern/JavaAsk.java new file mode 100644 index 0000000000..d2213cf3d1 --- /dev/null +++ b/akka-docs/rst/java/code/docs/pattern/JavaAsk.java @@ -0,0 +1,45 @@ +public class JavaAsk extends UntypedActor { + private ActorRef targetActor; + private ActorRef caller; + + private static class AskParam { + Props props; + Object message; + AskParam(Props props, Object message) { + this.props = props; + this.message = message; + } + } + + @Override + public SupervisorStrategy supervisorStrategy() { + return new OneForOneStrategy(0, Duration.Zero(), new Function() { + public Directive apply(Throwable cause) { + caller.tell(new Status.Failure(cause)); + return SupervisorStrategy.stop(); + } + }); + } + + @Override + public void onReceive(Object message) throws Exception { + if (message instanceof AskParam) { + AskParam param = (AskParam) message; + caller = getSender(); + targetActor = getContext().actorOf(param.props); + targetActor.forward(param.message, getContext()); + } else + unhandled(message); + } + + public static void ask(ActorSystem system, Props props, Object message, Timeout timeout) throws Exception { + ActorRef javaAsk = system.actorOf(Props.apply(JavaAsk.class)); + try { + AskParam param = new AskParam(props, message); + Future finished = Patterns.ask(javaAsk, param, timeout); + Await.result(finished, timeout.duration()); + } finally { + system.stop(javaAsk); + } + } +} \ No newline at end of file diff --git a/akka-docs/rst/java/howto.rst b/akka-docs/rst/java/howto.rst index 204d50e7dc..4778fae80b 100644 --- a/akka-docs/rst/java/howto.rst +++ b/akka-docs/rst/java/howto.rst @@ -1,4 +1,3 @@ - .. _howto-java: ###################### @@ -17,6 +16,90 @@ sense to add to the ``akka.pattern`` package for creating an `OTP-like library You might find some of the patterns described in the Scala chapter of :ref:`howto-scala` useful even though the example code is written in Scala. +Exception propagation in actor hierarchy using supervision +========================================================== + +*Contributed by: Rick Latrine* + +A nice way to enter the actor world from java is the use of Patterns.ask(). +This method starts a temporary actor to forward the message and collect the result from the actor to be "asked". +In case of errors within the asked actor the default supervision handling will take over. +The caller of Patterns.ask() will not be notified. + +If that caller is interested in such an exception, he must reply to the temporary actor with Status.Failure(Throwable). +Behind the asked actor a complex actor hierarchy might be spawned to accomplish asynchronous work. +Then supervision is the established way to control error handling. + +Unfortunately the asked actor must know about supervision and must catch the exceptions. +Such an actor is unlikely to be reused in a different actor hierarchy and contains crippled try/catch blocks. + +This pattern provides a way to encapsulate supervision and error propagation to the temporary actor. +Finally the exception occurred in the asked actor is thrown by Patterns.ask(). + +Let's have a look at the example code: + +.. code-block:: java + + public class JavaAsk extends UntypedActor { + private ActorRef targetActor; + private ActorRef caller; + + private static class AskParam { + Props props; + Object message; + AskParam(Props props, Object message) { + this.props = props; + this.message = message; + } + } + + @Override + public SupervisorStrategy supervisorStrategy() { + return new OneForOneStrategy(0, Duration.Zero(), new Function() { + public Directive apply(Throwable cause) { + caller.tell(new Status.Failure(cause)); + return SupervisorStrategy.stop(); + } + }); + } + + @Override + public void onReceive(Object message) throws Exception { + if (message instanceof AskParam) { + AskParam param = (AskParam) message; + caller = getSender(); + targetActor = getContext().actorOf(param.props); + targetActor.forward(param.message, getContext()); + } else + unhandled(message); + } + + public static void ask(ActorSystem system, Props props, Object message, Timeout timeout) throws Exception { + ActorRef javaAsk = system.actorOf(Props.apply(JavaAsk.class)); + try { + AskParam param = new AskParam(props, message); + Future finished = Patterns.ask(javaAsk, param, timeout); + Await.result(finished, timeout.duration()); + } finally { + system.stop(javaAsk); + } + } + } + } + +In the ask method the parent actor is started. +The parent is sent which child it should create and which message is to be forwarded. + +On receiving these parameteres the parent actor creates the target/child actor. +The message is forwarded in order to let the child actor reply the result directly to the temporary actor. + +In case of an exception the supervisor tells the temporary actor which exception was thrown. +Afterwards the actor hierarchy is stopped. +The exception will be thrown by the ask method. + +Finally we are able to execute an actor and receive the results or exceptions synchronously. + + Template Pattern ================