UntypedActor hooks default to super.<whatever> now, plus updated ScalaDoc

This commit is contained in:
Roland 2011-12-14 12:47:44 +01:00
parent 488576c62a
commit 7d6c74d75c
3 changed files with 104 additions and 78 deletions

View file

@ -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': * Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model':
* <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a> * <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a>
* <p/>
* An actor has a well-defined (non-cyclic) life-cycle.
* <pre>
* => RUNNING (created and started actor) - can receive messages
* => SHUTDOWN (when 'stop' or 'exit' is invoked) - can't do anything
* </pre>
* *
* <p/> * An actor has a well-defined (non-cyclic) life-cycle.
* The Actor's own ActorRef is available in the 'self' member variable. * - ''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
* messages 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 dont 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 { trait Actor {
@ -218,25 +247,8 @@ trait Actor {
final def sender: ActorRef = context.sender final def sender: ActorRef = context.sender
/** /**
* User overridable callback/setting. * This defines the initial actor behavior, it must return a partial function
* <p/> * with the actor logic.
* Partial function implementing the actor logic.
* To be implemented by concrete actor class.
* <p/>
* Example code:
* <pre>
* def receive = {
* case Ping =&gt;
* println("got a 'Ping' message")
* sender ! "pong"
*
* case OneWay =&gt;
* println("got a 'OneWay' message")
*
* case unknown =&gt;
* println("unknown message: " + unknown)
* }
* </pre>
*/ */
protected def receive: Receive protected def receive: Receive
@ -258,11 +270,10 @@ trait Actor {
def postStop() {} def postStop() {}
/** /**
* User overridable callback. * User overridable callback: '''By default it disposes of all children and then calls `postStop()`.'''
* <p/> * <p/>
* Is called on a crashed Actor right BEFORE it is restarted to allow clean * Is called on a crashed Actor right BEFORE it is restarted to allow clean
* up of resources before Actor is terminated. * up of resources before Actor is terminated.
* By default it disposes of all children calls postStop().
*/ */
def preRestart(reason: Throwable, message: Option[Any]) { def preRestart(reason: Throwable, message: Option[Any]) {
context.children foreach (context.stop(_)) context.children foreach (context.stop(_))
@ -270,10 +281,9 @@ trait Actor {
} }
/** /**
* User overridable callback. * User overridable callback: By default it calls `preStart()`.
* <p/> * <p/>
* Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash. * 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() } def postRestart(reason: Throwable) { preStart() }
@ -281,7 +291,9 @@ trait Actor {
* User overridable callback. * User overridable callback.
* <p/> * <p/>
* Is called when a message isn't handled by the current behavior of the actor * 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) { def unhandled(message: Any) {
message match { message match {

View file

@ -365,18 +365,12 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor
def stop(actor: ActorRef): Unit = { def stop(actor: ActorRef): Unit = {
implicit val timeout = settings.CreationTimeout implicit val timeout = settings.CreationTimeout
val path = actor.path val path = actor.path
if (path.parent == guardian.path) { val guard = guardian.path
(guardian ? StopChild(actor)).get match { val sys = systemGuardian.path
case ex: Exception throw ex path.parent match {
case _ case `guard` (guardian ? StopChild(actor)).get
} case `sys` (systemGuardian ? StopChild(actor)).get
} else if (path.parent == systemGuardian.path) { case _ actor.asInstanceOf[InternalActorRef].stop()
(systemGuardian ? StopChild(actor)).get match {
case ex: Exception throw ex
case _
}
} else {
actor.asInstanceOf[InternalActorRef].stop()
} }
} }

View file

@ -8,46 +8,67 @@ import akka.japi.{ Creator, Procedure }
import akka.dispatch.{ MessageDispatcher, Promise } 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':
* <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a>
*
* This class is the Java cousin to the [[akka.actor.Actor]] Scala interface.
* Subclass this abstract class to create a MDB-style untyped actor. * Subclass this abstract class to create a MDB-style untyped actor.
* <p/> *
* This class is meant to be used from Java. * An actor has a well-defined (non-cyclic) life-cycle.
* <p/> * - ''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
* messages 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: * Here is an example on how to create and use an UntypedActor:
* <pre> *
* {{{
* public class SampleUntypedActor extends 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 { * public void onReceive(Object message) throws Exception {
* if (message instanceof String) { * if (message instanceof String) {
* String msg = (String)message; * String msg = (String)message;
* *
* if (msg.equals("UseReply")) { * if (msg.equals("UseSender")) {
* // Reply to original sender of message using the 'reply' method * // Reply to original sender of message
* getContext().getSender().tell(msg + ":" + getSelf().getAddress()); * getSender().tell(msg + ":" + getSelf());
*
* } 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());
* *
* } else if (msg.equals("SendToSelf")) { * } else if (msg.equals("SendToSelf")) {
* // Send message to the actor itself recursively * // Send message to the actor itself recursively
* getSelf().tell(msg) * getSelf().tell("SomeOtherMessage");
* *
* } else if (msg.equals("ForwardMessage")) { * } else if (msg.equals("ErrorKernelWithDirectReply")) {
* // Retreive an actor from the ActorRegistry by ID and get an ActorRef back * // Send work to one-off child which will reply directly to original sender
* ActorRef actorRef = Actor.registry.local.actorsFor("some-actor-id").head(); * 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 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); * } 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();
* } * }
* } * }}}
* </pre>
*/ */
abstract class UntypedActor extends Actor { abstract class UntypedActor extends Actor {
@ -65,8 +86,9 @@ abstract class UntypedActor extends Actor {
def getSelf(): ActorRef = self def getSelf(): ActorRef = self
/** /**
* The reference sender Actor of the last received message. * The reference sender Actor of the currently processed message. This is
* Is defined if the message was sent from another Actor, else None. * 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 def getSender(): ActorRef = sender
@ -77,7 +99,7 @@ abstract class UntypedActor extends Actor {
* Actor are automatically started asynchronously when created. * Actor are automatically started asynchronously when created.
* Empty default implementation. * Empty default implementation.
*/ */
override def preStart() {} override def preStart(): Unit = super.preStart()
/** /**
* User overridable callback. * User overridable callback.
@ -85,24 +107,22 @@ abstract class UntypedActor extends Actor {
* Is called asynchronously after 'actor.stop()' is invoked. * Is called asynchronously after 'actor.stop()' is invoked.
* Empty default implementation. * 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()`.'''
* <p/> * <p/>
* Is called on a crashed Actor right BEFORE it is restarted to allow clean * Is called on a crashed Actor right BEFORE it is restarted to allow clean
* up of resources before Actor is terminated. * 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()`.
* <p/> * <p/>
* Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash. * 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. * User overridable callback.