add and verify Java API for actorFor/ActorPath, fixes #1343

This commit is contained in:
Roland 2011-12-07 11:41:54 +01:00
parent 56dc18106b
commit a0a44abe0d
6 changed files with 80 additions and 31 deletions

View file

@ -51,7 +51,11 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
system.actorFor(system / "c1") must be === c1
system.actorFor(system / "c2") must be === c2
system.actorFor(system / "c2" / "c21") must be === c21
system.actorFor(system child "c2" child "c21") must be === c21 // test Java API
system.actorFor(system / Seq("c2", "c21")) must be === c21
import scala.collection.JavaConverters._
system.actorFor(system descendant Seq("c2", "c21").asJava) // test Java API
}
"find actors by looking up their string representation" in {
@ -75,7 +79,7 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
"find actors by looking up their path elements" in {
system.actorFor(c1.path.elements) must be === c1
system.actorFor(c2.path.elements) must be === c2
system.actorFor(c21.path.elements) must be === c21
system.actorFor(c21.path.getElements) must be === c21 // test Java API
}
"find system-generated actors" in {
@ -190,6 +194,8 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
}
"return deadLetters for non-existing paths" in {
import scala.collection.JavaConverters._
def checkOne(looker: ActorRef, query: Query) {
(looker ? query).get must be === system.deadLetters
}
@ -198,6 +204,8 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
LookupString(""),
LookupString("akka://all-systems/Nobody"),
LookupPath(system / "hallo"),
LookupPath(looker.path child "hallo"), // test Java API
LookupPath(looker.path descendant Seq("a", "b").asJava), // test Java API
LookupElems(Seq()),
LookupElems(Seq("a"))) foreach (checkOne(looker, _))
}

View file

@ -49,16 +49,37 @@ sealed trait ActorPath extends Comparable[ActorPath] {
*/
def /(child: String): ActorPath
/**
* ''Java API'': Create a new child actor path.
*/
def child(child: String): ActorPath = /(child)
/**
* Recursively create a descendants path by appending all child names.
*/
def /(child: Iterable[String]): ActorPath = (this /: child)(_ / _)
/**
* Sequence of names for this path. Performance implication: has to allocate a list.
* ''Java API'': Recursively create a descendants path by appending all child names.
*/
def descendant(names: java.lang.Iterable[String]): ActorPath = {
import scala.collection.JavaConverters._
/(names.asScala)
}
/**
* Sequence of names for this path from root to this. Performance implication: has to allocate a list.
*/
def elements: Iterable[String]
/**
* ''Java API'': Sequence of names for this path from root to this. Performance implication: has to allocate a list.
*/
def getElements: java.lang.Iterable[String] = {
import scala.collection.JavaConverters._
elements.asJava
}
/**
* Walk up the tree to obtain and return the RootActorPath.
*/

View file

@ -178,7 +178,7 @@ private[akka] abstract class InternalActorRef extends ActorRef with ScalaActorRe
* trailing "" element must be disregarded. If the requested path does not
* exist, return Nobody.
*/
def getChild(name: Iterable[String]): InternalActorRef
def getChild(name: Iterator[String]): InternalActorRef
}
private[akka] case object Nobody extends MinimalActorRef {
@ -256,26 +256,27 @@ class LocalActorRef private[akka] (
}
}
def getChild(names: Iterable[String]): InternalActorRef = {
def getChild(names: Iterator[String]): InternalActorRef = {
/*
* The idea is to recursively descend as far as possible with LocalActor
* Refs and hand over to that foreign child when we encounter it.
*/
@tailrec
def rec(ref: InternalActorRef, name: Iterable[String]): InternalActorRef = ref match {
case l: LocalActorRef
val n = name.head
val rest = name.tail
val next = n match {
case ".." l.getParent
case "" l
case _ l.getSingleChild(n)
}
if (next == Nobody || rest.isEmpty) next else rec(next, rest)
case _
ref.getChild(name)
}
rec(this, names)
def rec(ref: InternalActorRef, name: Iterator[String]): InternalActorRef =
ref match {
case l: LocalActorRef
val n = name.next()
val next = n match {
case ".." l.getParent
case "" l
case _ l.getSingleChild(n)
}
if (next == Nobody || name.isEmpty) next else rec(next, name)
case _
ref.getChild(name)
}
if (names.isEmpty) this
else rec(this, names)
}
// ========= AKKA PROTECTED FUNCTIONS =========
@ -326,9 +327,11 @@ case class SerializedActorRef(path: String) {
trait MinimalActorRef extends InternalActorRef {
def getParent: InternalActorRef = Nobody
def getChild(name: Iterable[String]): InternalActorRef =
if (name.size == 1 && name.head.isEmpty) this
def getChild(names: Iterator[String]): InternalActorRef = {
val dropped = names.dropWhile(_.isEmpty)
if (dropped.isEmpty) this
else Nobody
}
//FIXME REMOVE THIS, ticket #1416
//FIXME REMOVE THIS, ticket #1415

View file

@ -287,7 +287,7 @@ trait ActorRefFactory {
def actorFor(path: Iterable[String]): ActorRef = provider.actorFor(lookupRoot, path)
/**
* Look-up an actor by applying the given path elements, starting from the
* ''Java API'': Look-up an actor by applying the given path elements, starting from the
* current context, where `".."` signifies the parent of an actor.
*
* Example:
@ -307,7 +307,7 @@ trait ActorRefFactory {
*
* For maximum performance use a collection with efficient head & tail operations.
*/
def actorFor(path: java.util.List[String]): ActorRef = {
def actorFor(path: java.lang.Iterable[String]): ActorRef = {
import scala.collection.JavaConverters._
provider.actorFor(lookupRoot, path.asScala)
}
@ -462,13 +462,17 @@ class LocalActorRefProvider(
val children = new ConcurrentHashMap[String, AskActorRef]
def path = tempNode
override def getParent = rootGuardian
override def getChild(name: Iterable[String]): InternalActorRef = {
children.get(name.head) match {
case null Nobody
case some
val t = name.tail
if (t.isEmpty) some
else some.getChild(t)
override def getChild(name: Iterator[String]): InternalActorRef = {
if (name.isEmpty) this
else {
val n = name.next()
if (n.isEmpty) this
else children.get(n) match {
case null Nobody
case some
if (name.isEmpty) some
else some.getChild(name)
}
}
}
}
@ -497,7 +501,7 @@ class LocalActorRefProvider(
def actorFor(ref: InternalActorRef, path: Iterable[String]): InternalActorRef =
if (path.isEmpty) deadLetters
else ref.getChild(path) match {
else ref.getChild(path.iterator) match {
case Nobody deadLetters
case x x
}

View file

@ -218,11 +218,24 @@ abstract class ActorSystem extends ActorRefFactory {
*/
def /(name: String): ActorPath
/**
* ''Java API'': Create a new child actor path.
*/
def child(child: String): ActorPath = /(child)
/**
* Construct a path below the application guardian to be used with [[ActorSystem.actorFor]].
*/
def /(name: Iterable[String]): ActorPath
/**
* ''Java API'': Recursively create a descendants path by appending all child names.
*/
def descendant(names: java.lang.Iterable[String]): ActorPath = {
import scala.collection.JavaConverters._
/(names.asScala)
}
/**
* Start-up time in milliseconds since the epoch.
*/

View file

@ -270,7 +270,7 @@ private[akka] case class RemoteActorRef private[akka] (
// FIXME RK
def getParent = Nobody
def getChild(name: Iterable[String]) = Nobody
def getChild(name: Iterator[String]) = Nobody
@volatile
private var running: Boolean = true