From cdff927e0e7d0950c54f7d042d143c6957a9336b Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 14 Dec 2011 19:34:08 +0100 Subject: [PATCH] remove non-user API from ActorContext, see #1516 - handleChildTerminated/handleFailure: no discussion - currentMessage was (ab)used by IO, fixed by down-casting which IO already does for writing to currentMessage (ewww) - Actor.apply() could now as well be moved to ActorCell, leaving Actor as user-API-only, which would be nice but not for M1 --- .../src/main/scala/akka/actor/Actor.scala | 3 +- .../src/main/scala/akka/actor/ActorCell.scala | 16 +---- .../src/main/scala/akka/actor/ActorRef.scala | 69 ++++++++++++------- akka-actor/src/main/scala/akka/actor/IO.scala | 8 +-- 4 files changed, 53 insertions(+), 43 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 72c4ecabc3..ad95d28238 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -307,7 +307,8 @@ trait Actor { // ========================================= private[akka] final def apply(msg: Any) = { - val behaviorStack = context.hotswap + // FIXME this should all go into ActorCell + val behaviorStack = context.asInstanceOf[ActorCell].hotswap msg match { case msg if behaviorStack.nonEmpty && behaviorStack.head.isDefinedAt(msg) ⇒ behaviorStack.head.apply(msg) case msg if behaviorStack.isEmpty && processingBehavior.isDefinedAt(msg) ⇒ processingBehavior.apply(msg) diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index be6bf2d1f4..d689be07c1 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -67,7 +67,7 @@ trait ActorContext extends ActorRefFactory { def setReceiveTimeout(timeout: Duration): Unit /** - * Resets the current receive timeout. + * Clears the receive timeout, i.e. deactivates this feature. */ def resetReceiveTimeout(): Unit @@ -83,16 +83,6 @@ trait ActorContext extends ActorRefFactory { */ def unbecome(): Unit - /** - * Returns the current message envelope. - */ - def currentMessage: Envelope - - /** - * Returns a stack with the hotswapped behaviors (as Scala PartialFunction). - */ - def hotswap: Stack[PartialFunction[Any, Unit]] - /** * Returns the sender 'ActorRef' of the current message. */ @@ -109,10 +99,6 @@ trait ActorContext extends ActorRefFactory { */ implicit def dispatcher: MessageDispatcher - def handleFailure(child: ActorRef, cause: Throwable): Unit - - def handleChildTerminated(child: ActorRef): Unit - /** * The system that the actor belongs to. * Importing this member will place a implicit MessageDispatcher in scope. diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index 7eab12c41b..1bdb9ae8ce 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -18,34 +18,57 @@ import akka.event.LoggingAdapter import java.util.concurrent.atomic.AtomicBoolean /** - * ActorRef is an immutable and serializable handle to an Actor. - *

- * Create an ActorRef for an Actor by using the factory method on the Actor object. - *

- * Here is an example on how to create an actor with a default constructor. - *

- *   import Actor._
+ * Immutable and serializable handle to an actor, which may or may not reside
+ * on the local host or inside the same [[akka.actor.ActorSystem]]. An ActorRef
+ * can be obtained from an [[akka.actor.ActorRefFactory]], an interface which
+ * is implemented by ActorSystem and [[akka.actor.ActorContext]]. This means
+ * actors can be created top-level in the ActorSystem or as children of an
+ * existing actor, but only from within that actor.
  *
- *   val actor = actorOf(Props[MyActor]
- *   actor ! message
- *   actor.stop()
- * 
+ * ActorRefs can be freely shared among actors by message passing. Message + * passing conversely is their only purpose, as demonstrated in the following + * examples: * - * You can also create and start actors like this: - *
- *   val actor = actorOf(Props[MyActor]
- * 
+ * Scala: + * {{{ + * class ExampleActor extends Actor { + * val other = context.actorOf(Props[OtherActor], "childName") // will be destroyed and re-created upon restart by default * - * Here is an example on how to create an actor with a non-default constructor. - *
- *   import Actor._
+ *   def receive {
+ *     case Request1(msg) => other ! refine(msg)     // uses this actor as sender reference, reply goes to us
+ *     case Request2(msg) => other.tell(msg, sender) // forward sender reference, enabling direct reply
+ *     case Request3(msg) => sender ! (other ? msg)  // will reply with a Future for holding other’s reply (implicit timeout from "akka.actor.timeout")
+ *   }
+ * }
+ * }}}
  *
- *   val actor = actorOf(Props(new MyActor(...))
- *   actor ! message
- *   actor.stop()
- * 
+ * Java: + * {{{ + * public class ExampleActor Extends UntypedActor { + * // this child will be destroyed and re-created upon restart by default + * final ActorRef other = getContext().actorOf(new Props(OtherActor.class), "childName"); * - * The natural ordering of ActorRef is defined in terms of its [[akka.actor.ActorPath]]. + * @Override + * public void onReceive(Object o) { + * if (o instanceof Request1) { + * val msg = ((Request1) o).getMsg(); + * other.tell(msg); // uses this actor as sender reference, reply goes to us + * + * } else if (o instanceof Request2) { + * val msg = ((Request2) o).getMsg(); + * other.tell(msg, getSender()); // forward sender reference, enabling direct reply + * + * } else if (o instanceof Request3) { + * val msg = ((Request3) o).getMsg(); + * getSender().tell(other.ask(msg, 5000)); // reply with Future for holding the other’s reply (timeout 5 seconds) + * + * } + * } + * } + * }}} + * + * ActorRef does not have a method for terminating the actor it points to, use + * [[akka.actor.ActorRefFactory]]`.stop(child)` for this purpose. */ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable { scalaRef: InternalActorRef ⇒ diff --git a/akka-actor/src/main/scala/akka/actor/IO.scala b/akka-actor/src/main/scala/akka/actor/IO.scala index 1551eef2ec..28bad4f85e 100644 --- a/akka-actor/src/main/scala/akka/actor/IO.scala +++ b/akka-actor/src/main/scala/akka/actor/IO.scala @@ -46,15 +46,15 @@ object IO { override def asReadable = this def read(len: Int)(implicit actor: Actor with IO): ByteString @cps[IOSuspendable[Any]] = shift { cont: (ByteString ⇒ IOSuspendable[Any]) ⇒ - ByteStringLength(cont, this, actor.context.currentMessage, len) + ByteStringLength(cont, this, actor.context.asInstanceOf[ActorCell].currentMessage, len) } def read()(implicit actor: Actor with IO): ByteString @cps[IOSuspendable[Any]] = shift { cont: (ByteString ⇒ IOSuspendable[Any]) ⇒ - ByteStringAny(cont, this, actor.context.currentMessage) + ByteStringAny(cont, this, actor.context.asInstanceOf[ActorCell].currentMessage) } def read(delimiter: ByteString, inclusive: Boolean = false)(implicit actor: Actor with IO): ByteString @cps[IOSuspendable[Any]] = shift { cont: (ByteString ⇒ IOSuspendable[Any]) ⇒ - ByteStringDelimited(cont, this, actor.context.currentMessage, delimiter, inclusive, 0) + ByteStringDelimited(cont, this, actor.context.asInstanceOf[ActorCell].currentMessage, delimiter, inclusive, 0) } } @@ -158,7 +158,7 @@ trait IO { } run() case msg if _next ne Idle ⇒ - _messages enqueue context.currentMessage + _messages enqueue context.asInstanceOf[ActorCell].currentMessage case msg if _receiveIO.isDefinedAt(msg) ⇒ _next = reset { _receiveIO(msg); Idle } run()