tree路径匹配抽象(2)
博客专区 > lost_o0 的博客 > 博客详情
tree路径匹配抽象(2)
lost_o0 发表于3年前
tree路径匹配抽象(2)
  • 发表于 3年前
  • 阅读 24
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

接着上一篇的 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


共有 人打赏支持
粉丝 11
博文 36
码字总数 31139
×
lost_o0
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: