Adding support for user-controlled action for unmatched messages

This commit is contained in:
Viktor Klang 2010-11-07 14:33:34 +01:00
parent ad6252c023
commit 019d440ddf

View file

@ -76,6 +76,14 @@ class ActorKilledException private[akka](message: String) extends AkkaException(
class ActorInitializationException private[akka](message: String) extends AkkaException(message)
class ActorTimeoutException private[akka](message: String) extends AkkaException(message)
/**
* This message is thrown by default when an Actors behavior doesn't match a message
*/
case class UnhandledMessageException(msg: Any, ref: ActorRef) extends Exception {
override def getMessage() = "Actor %s does not handle [%s]".format(ref,msg)
override def fillInStackTrace() = this //Don't waste cycles generating stack trace
}
/**
* Actor factory module with factory methods for creating various kinds of Actors.
*
@ -387,6 +395,16 @@ trait Actor extends Logging {
*/
def postRestart(reason: Throwable) {}
/**
* User overridable callback.
* <p/>
* Is called when a message isn't handled by the current behavior of the actor
* by default it throws an UnhandledMessageException
*/
def unhandled(msg: Any){
throw new UnhandledMessageException(msg,self)
}
/**
* Is the actor able to handle the message passed in as arguments?
*/
@ -407,8 +425,9 @@ trait Actor extends Logging {
// ==== INTERNAL IMPLEMENTATION DETAILS ====
// =========================================
private[akka] def apply(msg: Any) = processingBehavior(msg)
private[akka] def apply(msg: Any) = fullBehavior(msg)
/*Processingbehavior and fullBehavior are duplicates so make sure changes are done to both */
private lazy val processingBehavior: Receive = {
lazy val defaultBehavior = receive
val actorBehavior: Receive = {
@ -426,6 +445,25 @@ trait Actor extends Logging {
}
actorBehavior
}
private lazy val fullBehavior: Receive = {
lazy val defaultBehavior = receive
val actorBehavior: Receive = {
case HotSwap(code) => become(code)
case RevertHotSwap => unbecome
case Exit(dead, reason) => self.handleTrapExit(dead, reason)
case Link(child) => self.link(child)
case Unlink(child) => self.unlink(child)
case UnlinkAndStop(child) => self.unlink(child); child.stop
case Restart(reason) => throw reason
case msg if !self.hotswap.isEmpty &&
self.hotswap.head.isDefinedAt(msg) => self.hotswap.head.apply(msg)
case msg if self.hotswap.isEmpty &&
defaultBehavior.isDefinedAt(msg) => defaultBehavior.apply(msg)
case unknown => unhandled(unknown) //This is the only line that differs from processingbehavior
}
actorBehavior
}
}
private[actor] class AnyOptionAsTypedOption(anyOption: Option[Any]) {