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':
* <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/>
* 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
* 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 {
@ -218,25 +247,8 @@ trait Actor {
final def sender: ActorRef = context.sender
/**
* User overridable callback/setting.
* <p/>
* 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>
* 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()`.'''
* <p/>
* 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()`.
* <p/>
* 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.
* <p/>
* 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 {

View file

@ -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()
}
}

View file

@ -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':
* <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.
* <p/>
* This class is meant to be used from Java.
* <p/>
*
* 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
* 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:
* <pre>
*
* {{{
* 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();
* }
* }
* </pre>
* }}}
*/
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()`.'''
* <p/>
* 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()`.
* <p/>
* 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.