All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.Name.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finagle

import java.net.SocketAddress
import com.twitter.util.Var
import com.twitter.finagle.util.Showable

/**
 * Names identify network locations. They come in two varieties:
 *
 *  1. [[com.twitter.finagle.Name.Bound Bound]] names are concrete.
 *  They represent a changeable list of network endpoints
 *  (represented by [[com.twitter.finagle.Addr Addr]]s).
 *
 *  2. [[com.twitter.finagle.Name.Path Path]] names are unbound
 *  paths, representing an abstract location which must be resolved
 *  by some context, usually the [[com.twitter.finagle.Dtab Dtab]].
 */
sealed trait Name

object Name {
  /**
   * Path names comprise a [[com.twitter.finagle.Path Path]] denoting a
   * network location.
   */
  case class Path(path: com.twitter.finagle.Path) extends Name

  /**
   * Bound names comprise a changeable [[com.twitter.finagle.Addr
   * Addr]] which carries a host list of internet addresses.
   *
   * Equality of two Names is delegated to `id`. Two Bound instances
   * are equal whenever their `id`s are.
   */
  class Bound private(val addr: Var[Addr], val id: Any) extends Name with Proxy {
    def self = id

    // Workaround for https://issues.scala-lang.org/browse/SI-4807
    def canEqual(that: Any) = true
  }

  object Bound {
    def apply(addr: Var[Addr], id: Any): Name.Bound = new Bound(addr, id)
    def unapply(name: Name.Bound): Option[Var[Addr]] = Some(name.addr)

    /**
     * Create a singleton address, equal only to itself.
     */
    def singleton(addr: Var[Addr]): Name.Bound = Name.Bound(addr, new{})
  }

  // So that we can print NameTree[Name]
  implicit val showable: Showable[Name] = new Showable[Name] {
    def show(name: Name) = name match {
      case Path(path) => path.show
      case bound@Bound(_) => bound.id.toString
    }
  }

  /**
   * Create a pre-bound address.
   */
  def bound(addrs: SocketAddress*): Name.Bound = 
    Name.Bound(Var.value(Addr.Bound(addrs:_*)), addrs.toSet)

  /**
   * An always-empty name.
   */
  val empty: Name.Bound = bound()

  /**
   * Create a name from a group.
   *
   * @note Full Addr semantics cannot be recovered from Group. We
   * take a conservative approach here: we will only provide bound
   * addresses. Empty sets could indicate either pending or negative
   * resolutions.
   */
  def fromGroup(g: Group[SocketAddress]): Name.Bound = g match {
    case NameGroup(name) => name
    case group => Name.Bound({
       // Group doesn't support the abstraction of "not yet bound" so
       // this is a bit of a hack
       @volatile var first = true

       group.set map {
         case newSet if first && newSet.isEmpty => Addr.Pending
         case newSet =>
           first = false
           Addr.Bound(newSet)
       }
     }, group)
  }

  /**
   * Create a path-based Name which is interpreted vis-à-vis
   * the current request-local delegation table.
   */
  def apply(path: com.twitter.finagle.Path): Name = 
    Name.Path(path)

  /**
   * Create a path-based Name which is interpreted vis-à-vis
   * the current request-local delegation table.
   */
  def apply(path: String): Name =
    Name.Path(com.twitter.finagle.Path.read(path))

  /**
   * Create a name representing the union of the passed-in
   * names.
   */
  def all(names: Set[Name.Bound]): Name.Bound = 
    if (names.isEmpty) empty
    else if (names.size == 1) names.head
    else {
      val va = Var.collect(names map(_.addr)) map {
        case addrs if addrs.exists({case Addr.Bound(_) => true; case _ => false}) =>
          Addr.Bound((addrs flatMap {
            case Addr.Bound(as) => as
            case _ => Set.empty: Set[SocketAddress]
          }).toSet)
    
        case addrs if addrs.forall(_ == Addr.Neg) => Addr.Neg
        case addrs if addrs.forall({case Addr.Failed(_) => true; case _ => false}) =>
          Addr.Failed(new Exception)
    
        case _ => Addr.Pending
      }
      
      val id = names map { case [email protected](_) => bound.id }
      Name.Bound(va, id)
    }

  // A temporary bridge API to wait for some other changes to land.
  // Do not use.
  def DONOTUSE_nameToGroup(name: Name): Group[SocketAddress] = {
    val [email protected](_) = name
    NameGroup(bound)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy