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

com.twitter.finagle.serverset2.client.ClientBuilder.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finagle.serverset2.client

import com.twitter.conversions.time._
import com.twitter.util.{Duration, Timer}
import com.twitter.finagle.stats.{DefaultStatsReceiver, StatsReceiver}
import com.twitter.io.Buf
import com.twitter.finagle.util.{DefaultTimer, LoadService}
import java.net.InetSocketAddress

private[serverset2] sealed trait Capability
private[serverset2] object Reader extends Capability
private[serverset2] object Writer extends Capability
private[serverset2] object Multi extends Capability

private[serverset2] trait ClientFactory[T <: ZooKeeperClient] {
  val capabilities: Seq[Capability]
  val priority: Int
  def newClient(config: ClientConfig): Watched[T]
}

private[client] case class ClientConfig(
    val hosts: String,
    val sessionTimeout: Duration,
    val statsReceiver: StatsReceiver,
    val readOnlyOK: Boolean,
    val sessionId: Option[Long],
    val password: Option[Buf],
    val timer: Timer)
{
  def toMap: Map[String, Any] = Map(
    "hosts" -> hosts,
    "sessionTimeout" -> sessionTimeout,
    "statsReceiver" -> statsReceiver,
    "readOnlyOK" -> readOnlyOK,
    "sessionId" -> sessionId,
    "password" -> password,
    "timer" -> timer
  )

  override def toString = {
    "ClientConfig(%s)".format(
      toMap flatMap {
        case (k, Some(v)) =>
          Some("%s=%s".format(k, v))
        case _ =>
          None
      } mkString(", "))
  }
}

/**
 * Build a ZooKeeper Client.
 *
 * Configure:
 *
 * hosts(hosts) sets a list of ZooKeeper hosts:ports to connect to ["localhost:2181"]
 * sessionTimeout(timeout) sets ZooKeeper session timeout [10.seconds]
 * statsReceiver(receiver) sets Stats Receiver for client stats. [DefaultStatsReceiver]
 * readOnlyOK() enables read-only support from disconnected observers. [False]
 * sessionId(id) sets session ID for reconnection. [None]
 * password(pwd) sets session Password for reconnection. [None]
 * timer(timer) sets Timer [DefaultTimer.twitter]
 *
 * Build:
 *
 * reader() builds Read Only client.
 * writer() builds Read/Write client.
 * multi() builds Read/Write/Multi client.
 */
private[serverset2] object ClientBuilder {
  private val DefaultConfig: ClientConfig = ClientConfig(
    hosts = "localhost:2181",
    sessionTimeout = 10.seconds,
    statsReceiver = DefaultStatsReceiver.scope("zkclient"),
    readOnlyOK = false,
    sessionId = None,
    password = None,
    timer = DefaultTimer.twitter
  )

  def apply() = new ClientBuilder(DefaultConfig)

  /**
   * Used for Java access.
   */
  def get() = apply()
}

private[client] class ClientBuilder(config: ClientConfig) {
  private def resolve[T <: ZooKeeperClient](cap: Capability) = LoadService[ClientFactory[T]]()
      .filter(_.capabilities.contains(cap))
      .sortBy(_.priority) match {
    case Seq() => throw new RuntimeException("No ZooKeeper ClientFactory Found")
    case Seq(f, _*) => f
  }

  override def toString() = "ClientBuilder(%s)".format(config.toString)

  protected def copy(config: ClientConfig): ClientBuilder = new ClientBuilder(config)

  protected def withConfig(f: ClientConfig => ClientConfig): ClientBuilder = copy(f(config))

  /**
   * Create a new ZooKeeperReader client.
   *
   * @return configured Watched[ZooKeeperReader]
   * @throws RuntimeException if no matching ClientFactories are found.
   */
  def reader(): Watched[ZooKeeperReader] =
    resolve[ZooKeeperReader](Reader).newClient(config)

  /**
   * Create a new ZooKeeperRW client.
   *
   * @return configured Watched[ZooKeeperRW]
   * @throws RuntimeException if no matching ClientFactories are found.
   */
  def writer(): Watched[ZooKeeperRW] =
    resolve[ZooKeeperRW](Writer).newClient(config)

  /**
   * Create a new ZooKeeperRWMulti client.
   *
   * @return configured Watched[ZooKeeperRWMulti]
   * @throws RuntimeException if no matching ClientFactories are found.
   */
  def multi(): Watched[ZooKeeperRWMulti] =
    resolve[ZooKeeperRWMulti](Multi).newClient(config)

  /**
   * Configure builder with list of ZooKeeper servers in an ensemble.
   *
   * @param zkHosts comma separated host:port list.
   * @return configured ClientBuilder
   */
  def hosts(zkHosts: String): ClientBuilder = withConfig(_.copy(hosts = zkHosts))

  /**
   * Configure builder with list of ZooKeeper servers in an ensemble.
   *
   * @param zkHosts sequence of InetSocketAddresses.
   * @return configured ClientBuilder
   */
  def hosts(zkHosts: Seq[InetSocketAddress]): ClientBuilder =
    hosts(zkHosts.map { h => "%s:%d,".format(h.getHostName, h.getPort) }.mkString)

  /**
   * Configure builder with a session timeout.
   *
   * @param zkTimeout duration.
   * @return configured ClientBuilder
   */
  def sessionTimeout(zkTimeout: Duration): ClientBuilder =
    withConfig(_.copy(sessionTimeout = zkTimeout))

  /**
   * Configure builder with a Stats Receiver.
   *
   * @param statsIn stats receiver.
   * @return configured ClientBuilder
   */
  def statsReceiver(statsIn: StatsReceiver): ClientBuilder =
    withConfig(_.copy(statsReceiver = statsIn))

  /**
   * Enable read-only support from disconnected observers.
   *
   * This feature is not supported by all implementations.
   *
   * When a ZooKeeper ensemble loses quorum, observers may choose to allow
   * clients to continue to read data, which may be out of date. This is
   * NOT advised for clients that desire consistency over availability.
   *
   * @return configured ClientBuilder
   */
  def readOnlyOK(): ClientBuilder =
    withConfig(_.copy(readOnlyOK = true))

  /**
   * Configure builder with a session ID for reconnection.
   *
   * @param sessionId existing session ID.
   * @return configured ClientBuilder
   */
  def sessionId(sessionId: Long): ClientBuilder =
    withConfig(_.copy(sessionId = Some(sessionId)))

  /**
   * Configure builder with a session password for reconnection.
   *
   * @param password existing session password.
   * @return configured ClientBuilder
   */
  def password(password: Buf): ClientBuilder =
    withConfig(_.copy(password = Some(password)))

  /**
   * Configure builder with a new timer.
   *
   * @param timer Timer to use.
   * @return configured ClientBuilder
   */
  def timer(timer:Timer): ClientBuilder =
    withConfig(_.copy(timer = timer))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy