2012-01-20 14:29:50 +01:00
|
|
|
/**
|
2012-05-21 16:45:15 +02:00
|
|
|
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
2012-01-20 14:29:50 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.remote
|
|
|
|
|
|
|
|
|
|
import scala.annotation.tailrec
|
|
|
|
|
|
2012-01-31 21:19:28 +01:00
|
|
|
import akka.actor.{ VirtualPathContainer, Terminated, Deploy, Props, Nobody, LocalActorRef, InternalActorRef, Address, ActorSystemImpl, ActorRef, ActorPathExtractor, ActorPath, Actor }
|
2012-01-20 14:29:50 +01:00
|
|
|
import akka.event.LoggingAdapter
|
2012-05-28 16:49:49 +02:00
|
|
|
import akka.dispatch.Watch
|
2012-01-20 14:29:50 +01:00
|
|
|
|
2012-02-03 09:43:23 +01:00
|
|
|
private[akka] sealed trait DaemonMsg
|
|
|
|
|
private[akka] case class DaemonMsgCreate(props: Props, deploy: Deploy, path: String, supervisor: ActorRef) extends DaemonMsg
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Internal system "daemon" actor for remote internal communication.
|
|
|
|
|
*
|
|
|
|
|
* It acts as the brain of the remote that responds to system remote events (messages) and undertakes action.
|
2012-01-30 11:48:02 +01:00
|
|
|
*
|
|
|
|
|
* INTERNAL USE ONLY!
|
2012-01-20 14:29:50 +01:00
|
|
|
*/
|
2012-01-30 11:48:02 +01:00
|
|
|
private[akka] class RemoteSystemDaemon(system: ActorSystemImpl, _path: ActorPath, _parent: InternalActorRef, _log: LoggingAdapter)
|
2012-01-26 11:24:23 +01:00
|
|
|
extends VirtualPathContainer(system.provider, _path, _parent, _log) {
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Find the longest matching path which we know about and return that ref
|
|
|
|
|
* (or ask that ref to continue searching if elements are left).
|
|
|
|
|
*/
|
|
|
|
|
override def getChild(names: Iterator[String]): InternalActorRef = {
|
|
|
|
|
|
|
|
|
|
@tailrec
|
|
|
|
|
def rec(s: String, n: Int): (InternalActorRef, Int) = {
|
|
|
|
|
getChild(s) match {
|
|
|
|
|
case null ⇒
|
|
|
|
|
val last = s.lastIndexOf('/')
|
|
|
|
|
if (last == -1) (Nobody, n)
|
|
|
|
|
else rec(s.substring(0, last), n + 1)
|
|
|
|
|
case ref ⇒ (ref, n)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val full = Vector() ++ names
|
|
|
|
|
rec(full.mkString("/"), 0) match {
|
|
|
|
|
case (Nobody, _) ⇒ Nobody
|
|
|
|
|
case (ref, 0) ⇒ ref
|
|
|
|
|
case (ref, n) ⇒ ref.getChild(full.takeRight(n).iterator)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override def !(msg: Any)(implicit sender: ActorRef = null): Unit = msg match {
|
|
|
|
|
case message: DaemonMsg ⇒
|
|
|
|
|
log.debug("Received command [{}] to RemoteSystemDaemon on [{}]", message, path.address)
|
|
|
|
|
message match {
|
2012-01-31 21:19:28 +01:00
|
|
|
case DaemonMsgCreate(props, deploy, path, supervisor) ⇒
|
2012-01-20 14:29:50 +01:00
|
|
|
path match {
|
2012-01-27 12:14:28 +01:00
|
|
|
case ActorPathExtractor(address, elems) if elems.nonEmpty && elems.head == "remote" ⇒
|
|
|
|
|
// TODO RK currently the extracted “address” is just ignored, is that okay?
|
2012-01-20 14:29:50 +01:00
|
|
|
// TODO RK canonicalize path so as not to duplicate it always #1446
|
|
|
|
|
val subpath = elems.drop(1)
|
|
|
|
|
val path = this.path / subpath
|
2012-01-31 21:19:28 +01:00
|
|
|
val actor = system.provider.actorOf(system, props, supervisor.asInstanceOf[InternalActorRef],
|
|
|
|
|
path, false, Some(deploy), true)
|
2012-01-20 14:29:50 +01:00
|
|
|
addChild(subpath.mkString("/"), actor)
|
2012-05-28 16:49:49 +02:00
|
|
|
this.sendSystemMessage(Watch(actor, this))
|
2012-01-20 14:29:50 +01:00
|
|
|
case _ ⇒
|
|
|
|
|
log.error("remote path does not match path from message [{}]", message)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case Terminated(child: LocalActorRef) ⇒ removeChild(child.path.elements.drop(1).mkString("/"))
|
|
|
|
|
|
2012-05-29 14:09:22 +02:00
|
|
|
case t: Terminated ⇒
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
|
|
|
case unknown ⇒ log.warning("Unknown message {} received by {}", unknown, this)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|