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

com.loopfor.zookeeper.Configuration.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013 David Edwards
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.loopfor.zookeeper

import java.net.InetSocketAddress
import scala.concurrent.ExecutionContext
import scala.concurrent.duration._
import scala.language._

/**
 * A client ''configuration'' for connecting to a ZooKeeper cluster.
 */
trait Configuration {
  /**
   * Returns a sequence of server endpoints in this cluster.
   * 
   * These endpoints do not necessarily need to reflect all servers in the cluster, only those to which the client desires to
   * make a possible connection.
   * 
   * @return a sequence of socket addresses
   */
  def servers: Seq[InetSocketAddress]

  /**
   * Returns an optional root path.
   * 
   * @return the root path if specified, otherwise an empty string
   */
  def path: String

  /**
   * Returns the period of time after which the session is expired.
   * 
   * Note that this value is only a proposal and that ZooKeeper may use a different timeout.
   * 
   * @return the session timeout
   */
  def timeout: Duration

  /**
   * Returns an optional function that is called when state changes occur in the session.
   * 
   * Note that a new session may be established if the client disconnects and reconnects to ZooKeeper, particularly with
   * respect to the session `id` and `password`.
   * 
   * @return a function that receives session state changes, otherwise `null` if not specified
   */
  def watcher: (StateEvent, Session) => Unit

  /**
   * Returns `true` if the client will allow read-only connections to ZooKeeper under conditions in which a majority of
   * servers cannot be established.
   * 
   * @return `true` if read-only is allowed, `false` otherwise
   */
  def allowReadOnly: Boolean

  /**
   * Returns an optional execution context to which asynchronous tasks are submitted.
   * 
   * Use this feature when an application container prefers to manage the execution context.
   * 
   * @return an execution context if specified, otherwise `null`
   */
  def exec: ExecutionContext
}

/**
 * Constructs and deconstructs [[Configuration]] values.
 * 
 * A configuration is constructed by first specifying ''required'' attributes via `Configuration()` and then attaching
 * ''optional'' attributes as necessary. A set of implicit methods conveniently convert between instances of [[Configuration]]
 * and [[Configuration.Builder Builder]].
 * 
 * Example:
 * {{{
 * val config = Configuration {
 *   ("foo.server.com", 2181) :: ("bar.server.com", 2181) :: Nil
 * } withTimeout {
 *   60 seconds
 * } withWatcher { (event, session) =>
 *   // ...
 * }
 * }}}
 * 
 * The type of `config` above is [[Configuration.Builder Builder]] since an implicit conversion occurred when attaching
 * optional attributes using the various `with` methods. An explicit conversion back to [[Configuration]], which can be
 * accomplished using `build()`, is unnecessary since another implicit will perform this function automatically.
 */
object Configuration {
  /**
   * Constructs a new default configuration using the given servers.
   * 
   * @param servers sequence of socket addresses corresponding to server endpoints
   * @return a default configuration with the given `servers`
   */
  def apply(servers: Seq[InetSocketAddress]): Configuration = new Builder(servers) build

  /**
   * Used in pattern matching to deconstruct a configuration.
   * 
   * @param config selector value
   * @return a `Some` containing configuration attributes if the selector value is not `null`, otherwise `None`
   */
  def unapply(config: Configuration): Option[(Seq[InetSocketAddress], String, Duration, (StateEvent, Session) => Unit,
        Boolean, ExecutionContext)] = {
    if (config == null)
      None
    else
      Some(config.servers, config.path, config.timeout, config.watcher, config.allowReadOnly, config.exec)
  }

  private class Impl(
        val servers: Seq[InetSocketAddress],
        val path: String,
        val timeout: Duration,
        val watcher: (StateEvent, Session) => Unit,
        val allowReadOnly: Boolean,
        val exec: ExecutionContext) extends Configuration

  class Builder private (
        servers: Seq[InetSocketAddress],
        path: String,
        timeout: Duration,
        watcher: (StateEvent, Session) => Unit,
        allowReadOnly: Boolean,
        exec: ExecutionContext) {
    private[Configuration] def this(servers: Seq[InetSocketAddress]) {
      this(servers, "", 60 seconds, null, false, null)
    }

    private[Configuration] def this(config: Configuration) {
      this(config.servers, config.path, config.timeout, config.watcher, config.allowReadOnly, config.exec)
    }

    def withPath(path: String): Builder =
      new Builder(servers, path, timeout, watcher, allowReadOnly, exec)

    def withTimeout(timeout: Duration): Builder =
      new Builder(servers, path, timeout, watcher, allowReadOnly, exec)

    def withWatcher(watcher: (StateEvent, Session) => Unit): Builder =
      new Builder(servers, path, timeout, watcher, allowReadOnly, exec)

    def withAllowReadOnly(allowReadOnly: Boolean): Builder =
      new Builder(servers, path, timeout, watcher, allowReadOnly, exec)

    def withExec(exec: ExecutionContext): Builder =
      new Builder(servers, path, timeout, watcher, allowReadOnly, exec)

    def build(): Configuration = new Impl(servers, path, timeout, watcher, allowReadOnly, exec)
  }

  implicit def configToBuilder(config: Configuration): Builder = new Builder(config)
  implicit def builderToConfig(builder: Builder): Configuration = builder.build
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy