标签:
接着上一篇的 tree路径匹配抽象(1),我们开始看如何对tree进行索引,akka的路径匹配包含了远程节点的匹配,这样就得引入多个通信机制(akka采用消息),为了简化,我们先假设只在一个本地tree中进行索引:
object ActorSelection {//...省略
/**
* Construct an ActorSelection from the given string representing a path
* relative to the given target. This operation has to create all the
* matching magic, so it is preferable to cache its result if the
* intention is to send messages frequently.
*/
def apply(anchorRef: ActorRef, path: String): ActorSelection = apply(anchorRef, path.split("/+"))//ActorRef可以被当作当前路径的引用
/**
* Construct an ActorSelection from the given string representing a path
* relative to the given target. This operation has to create all the
* matching magic, so it is preferable to cache its result if the
* intention is to send messages frequently.
*/
def apply(anchorRef: ActorRef, elements: Iterable[String]): ActorSelection = { val compiled: immutable.IndexedSeq[SelectionPathElement] = elements.collect({ case x if !x.isEmpty ? if ((x.indexOf(‘?‘) != -1) || (x.indexOf(‘*‘) != -1)) SelectChildPattern(x) else if (x == "..") SelectParent else SelectChildName(x)
})(scala.collection.breakOut)//直接转换为immutable.IndexedSeq[SelectionPathElement]
new ActorSelection with ScalaActorSelection { override val anchor = anchorRef override val path = compiled
}
}//------上面是将字符串转化为SelectionPathElement,下面则是根据SelectionPathElement进行索引tree值
/**
* INTERNAL API
* The receive logic for ActorSelectionMessage. The idea is to recursively descend as far as possible
* with local refs and hand over to that “foreign” child when we encounter it.
*/
private[akka] def deliverSelection(anchor: InternalActorRef, sender: ActorRef, sel: ActorSelectionMessage): Unit = if (sel.elements.isEmpty)
anchor.tell(sel.msg, sender)//自己
else { val iter = sel.elements.iterator @tailrec def rec(ref: InternalActorRef): Unit = {
ref match { case refWithCell: ActorRefWithCell ? def emptyRef = new EmptyLocalActorRef(refWithCell.provider, anchor.path / sel.elements.map(_.toString),
refWithCell.underlying.system.eventStream)
iter.next() match { case SelectParent ? val parent = ref.getParent if (iter.isEmpty)
parent.tell(sel.msg, sender) else
rec(parent) case SelectChildName(name) ? val child = refWithCell.getSingleChild(name) if (child == Nobody) { // don‘t send to emptyRef after wildcard fan-out
if (!sel.wildcardFanOut) emptyRef.tell(sel, sender)
} else if (iter.isEmpty)
child.tell(sel.msg, sender) else
rec(child) case p: SelectChildPattern ? // fan-out when there is a wildcard
val chldr = refWithCell.children if (iter.isEmpty) { // leaf
val matchingChildren = chldr.filter(c ? p.pattern.matcher(c.path.name).matches) if (matchingChildren.isEmpty && !sel.wildcardFanOut)
emptyRef.tell(sel, sender) else
matchingChildren.foreach(_.tell(sel.msg, sender))
} else { val matchingChildren = chldr.filter(c ? p.pattern.matcher(c.path.name).matches) // don‘t send to emptyRef after wildcard fan-out
if (matchingChildren.isEmpty && !sel.wildcardFanOut)
emptyRef.tell(sel, sender) else { val m = sel.copy(elements = iter.toVector,
wildcardFanOut = sel.wildcardFanOut || matchingChildren.size > 1)
matchingChildren.foreach(c ? deliverSelection(c.asInstanceOf[InternalActorRef], sender, m))
}
}
} //case _ ?
// foreign ref, continue by sending ActorSelectionMessage to it with remaining elements
//ref.tell(sel.copy(elements = iter.toVector), sender)
}
}
rec(anchor)
}
}
既然path允许正则索引,那么path最好有个命名规则,akka的命名规则为:
/**
* This Regular Expression is used to validate a path element (Actor Name).
* Since Actors form a tree, it is addressable using an URL, therefore an Actor Name has to conform to:
* http://www.ietf.org/rfc/rfc2396.txt
*/
val ElementRegex = """(?:[-\w:@&=+,.!~*‘_;]|%\p{XDigit}{2})(?:[-\w:@&=+,.!~*‘$_;]|%\p{XDigit}{2})*""".r
标签:
原文地址:http://my.oschina.net/myprogworld/blog/381197