diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 4c8877463c..72c4ecabc3 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -156,15 +156,44 @@ object Actor { /** * Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model': * http://en.wikipedia.org/wiki/Actor_model - *
- * An actor has a well-defined (non-cyclic) life-cycle. - *- * => RUNNING (created and started actor) - can receive messages - * => SHUTDOWN (when 'stop' or 'exit' is invoked) - can't do anything - ** - * - * The Actor's own ActorRef is available in the 'self' member variable. + * An actor has a well-defined (non-cyclic) life-cycle. + * - ''RUNNING'' (created and started actor) - can receive messages + * - ''SHUTDOWN'' (when 'stop' or 'exit' is invoked) - can't do anything + * + * The Actor's own [[akka.actor.ActorRef]] is available as `self`, the current + * message’s sender as `sender` and the [[akka.actor.ActorContext]] as + * `context`. The only abstract method is `receive` which shall return the + * initial behavior of the actor as a partial function (behavior can be changed + * using `context.become` and `context.unbecome`). + * + * {{{ + * class ExampleActor extends Actor { + * def receive = { + * // directly calculated reply + * case Request(r) => sender ! calculate(r) + * + * // just to demonstrate how to stop yourself + * case Shutdown => context.stop(self) + * + * // error kernel with child replying directly to “customer” + * case Dangerous(r) => context.actorOf(Props[ReplyToOriginWorker]).tell(PerformWork(r), sender) + * + * // error kernel with reply going through us + * case OtherJob(r) => context.actorOf(Props[ReplyToMeWorker]) ! JobRequest(r, sender) + * case JobReply(result, orig_s) => orig_s ! result + * } + * } + * }}} + * + * The last line demonstrates the essence of the error kernel design: spawn + * one-off actors which terminate after doing their job, pass on `sender` to + * allow direct reply if that is what makes sense, or round-trip the sender + * as shown with the fictitious JobRequest/JobReply message pair. + * + * If you don’t like writing `context` you can always `import context._` to get + * direct access to `actorOf`, `stop` etc. This is not default in order to keep + * the name-space clean. */ trait Actor { @@ -218,25 +247,8 @@ trait Actor { final def sender: ActorRef = context.sender /** - * User overridable callback/setting. - * - * Partial function implementing the actor logic. - * To be implemented by concrete actor class. - * - * Example code: - *
- * def receive = {
- * case Ping =>
- * println("got a 'Ping' message")
- * sender ! "pong"
- *
- * case OneWay =>
- * println("got a 'OneWay' message")
- *
- * case unknown =>
- * println("unknown message: " + unknown)
- * }
- *
+ * This defines the initial actor behavior, it must return a partial function
+ * with the actor logic.
*/
protected def receive: Receive
@@ -258,11 +270,10 @@ trait Actor {
def postStop() {}
/**
- * User overridable callback.
+ * User overridable callback: '''By default it disposes of all children and then calls `postStop()`.'''
*
* Is called on a crashed Actor right BEFORE it is restarted to allow clean
* up of resources before Actor is terminated.
- * By default it disposes of all children calls postStop().
*/
def preRestart(reason: Throwable, message: Option[Any]) {
context.children foreach (context.stop(_))
@@ -270,10 +281,9 @@ trait Actor {
}
/**
- * User overridable callback.
+ * User overridable callback: By default it calls `preStart()`.
*
* Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash.
- * By default it calls preStart()
*/
def postRestart(reason: Throwable) { preStart() }
@@ -281,7 +291,9 @@ trait Actor {
* User overridable callback.
*
* Is called when a message isn't handled by the current behavior of the actor
- * by default it does: EventHandler.warning(self, message)
+ * by default it fails with either a [[akka.actor.DeathPactException]] (in
+ * case of an unhandled [[akka.actor.Terminated]] message) or a
+ * [[akka.actor.UnhandledMessageException]].
*/
def unhandled(message: Any) {
message match {
diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala
index 26a81d5eba..f801f7120d 100644
--- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala
+++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala
@@ -365,18 +365,12 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor
def stop(actor: ActorRef): Unit = {
implicit val timeout = settings.CreationTimeout
val path = actor.path
- if (path.parent == guardian.path) {
- (guardian ? StopChild(actor)).get match {
- case ex: Exception ⇒ throw ex
- case _ ⇒
- }
- } else if (path.parent == systemGuardian.path) {
- (systemGuardian ? StopChild(actor)).get match {
- case ex: Exception ⇒ throw ex
- case _ ⇒
- }
- } else {
- actor.asInstanceOf[InternalActorRef].stop()
+ val guard = guardian.path
+ val sys = systemGuardian.path
+ path.parent match {
+ case `guard` ⇒ (guardian ? StopChild(actor)).get
+ case `sys` ⇒ (systemGuardian ? StopChild(actor)).get
+ case _ ⇒ actor.asInstanceOf[InternalActorRef].stop()
}
}
diff --git a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala
index 1692396a8f..13677f84cc 100644
--- a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala
+++ b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala
@@ -8,46 +8,67 @@ import akka.japi.{ Creator, Procedure }
import akka.dispatch.{ MessageDispatcher, Promise }
/**
+ * Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model':
+ * http://en.wikipedia.org/wiki/Actor_model
+ *
+ * This class is the Java cousin to the [[akka.actor.Actor]] Scala interface.
* Subclass this abstract class to create a MDB-style untyped actor.
- *
- * This class is meant to be used from Java.
- *
+ *
+ * An actor has a well-defined (non-cyclic) life-cycle.
+ * - ''RUNNING'' (created and started actor) - can receive messages
+ * - ''SHUTDOWN'' (when 'stop' or 'exit' is invoked) - can't do anything
+ *
+ * The Actor's own [[akka.actor.ActorRef]] is available as `getSelf()`, the current
+ * message’s sender as `getSender()` and the [[akka.actor.UntypedActorContext]] as
+ * `getContext()`. The only abstract method is `onReceive()` which is invoked for
+ * each processed message unless dynamically overridden using `getContext().become()`.
+ *
* Here is an example on how to create and use an UntypedActor:
- *
+ *
+ * {{{
* public class SampleUntypedActor extends UntypedActor {
+ *
+ * public class Reply {
+ * final public ActorRef sender;
+ * final public Result result;
+ * Reply(ActorRef sender, Result result) {
+ * this.sender = sender;
+ * this.result = result;
+ * }
+ * }
+ *
* public void onReceive(Object message) throws Exception {
* if (message instanceof String) {
* String msg = (String)message;
*
- * if (msg.equals("UseReply")) {
- * // Reply to original sender of message using the 'reply' method
- * getContext().getSender().tell(msg + ":" + getSelf().getAddress());
- *
- * } else if (msg.equals("UseSender") && getSender().isDefined()) {
- * // Reply to original sender of message using the sender reference
- * // also passing along my own reference (the self)
- * getSender().get().tell(msg, getSelf());
+ * if (msg.equals("UseSender")) {
+ * // Reply to original sender of message
+ * getSender().tell(msg + ":" + getSelf());
*
* } else if (msg.equals("SendToSelf")) {
* // Send message to the actor itself recursively
- * getSelf().tell(msg)
+ * getSelf().tell("SomeOtherMessage");
*
- * } else if (msg.equals("ForwardMessage")) {
- * // Retreive an actor from the ActorRegistry by ID and get an ActorRef back
- * ActorRef actorRef = Actor.registry.local.actorsFor("some-actor-id").head();
+ * } else if (msg.equals("ErrorKernelWithDirectReply")) {
+ * // Send work to one-off child which will reply directly to original sender
+ * getContext().actorOf(new Props(Worker.class)).tell("DoSomeDangerousWork", getSender());
+ *
+ * } else if (msg.equals("ErrorKernelWithReplyHere")) {
+ * // Send work to one-off child and collect the answer, reply handled further down
+ * getContext().actorOf(new Props(Worker.class)).tell("DoWorkAndReplyToMe");
*
* } else throw new IllegalArgumentException("Unknown message: " + message);
+ *
+ * } else if (message instanceof Reply) {
+ *
+ * final Reply reply = (Reply) message;
+ * // might want to do some processing/book-keeping here
+ * reply.sender.tell(reply.result);
+ *
* } else throw new IllegalArgumentException("Unknown message: " + message);
* }
- *
- * public static void main(String[] args) {
- * ActorSystem system = ActorSystem.create("Sample");
- * ActorRef actor = system.actorOf(SampleUntypedActor.class);
- * actor.tell("SendToSelf");
- * actor.stop();
- * }
* }
- *
+ * }}}
*/
abstract class UntypedActor extends Actor {
@@ -65,8 +86,9 @@ abstract class UntypedActor extends Actor {
def getSelf(): ActorRef = self
/**
- * The reference sender Actor of the last received message.
- * Is defined if the message was sent from another Actor, else None.
+ * The reference sender Actor of the currently processed message. This is
+ * always a legal destination to send to, even if there is no logical recipient
+ * for the reply, in which case it will be sent to the dead letter mailbox.
*/
def getSender(): ActorRef = sender
@@ -77,7 +99,7 @@ abstract class UntypedActor extends Actor {
* Actor are automatically started asynchronously when created.
* Empty default implementation.
*/
- override def preStart() {}
+ override def preStart(): Unit = super.preStart()
/**
* User overridable callback.
@@ -85,24 +107,22 @@ abstract class UntypedActor extends Actor {
* Is called asynchronously after 'actor.stop()' is invoked.
* Empty default implementation.
*/
- override def postStop() {}
+ override def postStop(): Unit = super.postStop()
/**
- * User overridable callback.
+ * User overridable callback: '''By default it disposes of all children and then calls `postStop()`.'''
*
* Is called on a crashed Actor right BEFORE it is restarted to allow clean
* up of resources before Actor is terminated.
- * By default it calls postStop()
*/
- override def preRestart(reason: Throwable, message: Option[Any]) { postStop() }
+ override def preRestart(reason: Throwable, message: Option[Any]): Unit = super.preRestart(reason, message)
/**
- * User overridable callback.
+ * User overridable callback: By default it calls `preStart()`.
*
* Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash.
- * By default it calls preStart()
*/
- override def postRestart(reason: Throwable) { preStart() }
+ override def postRestart(reason: Throwable): Unit = super.postRestart(reason)
/**
* User overridable callback.