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

com.quantifind.sumac.ZkArgs.scala Maven / Gradle / Ivy

The newest version!
package com.quantifind.sumac

import com.twitter.zk.{ZNode, ZkClient}
import com.twitter.conversions.time._
import com.twitter.util.{Duration, Timer, JavaTimer}
import collection.JavaConverters._
import collection._

/**
 * Add this into args to be able to read args from zookeeper.
 *
 * Note that it does *NOT* write the arguments back to zookeeper automatically.  This is because in general, zookeeper
 * would just be used to store some defaults, which you don't want to get overridden all the time.
 */
trait ZkArgs extends ExternalConfig {
  self: Args =>

  var zkConn: String = _
  var zkPaths: List[String] = List()

  val timeout = 5.seconds

  implicit lazy val timer = new JavaTimer(false)
  lazy val zkClient = ZkArgHelper.basicZkClient(zkConn, timeout)
  def saveToZk(zkPath: String) = {
    ZkArgHelper.saveArgsToZk(zkClient, zkPath, getStringValues)
  }

  abstract override def readArgs(originalArgs: Map[String,String]): Map[String,String] = {
    parse(originalArgs, false)
    val newArgs = zkPaths.foldLeft(originalArgs){case(prev, nextPath) =>
      val zkArgs = ZkArgHelper.getArgsFromZk(zkClient, nextPath)
      ExternalConfigUtil.mapWithDefaults(prev, zkArgs)
    }
    super.readArgs(newArgs)
  }

  abstract override def saveConfig() {
    //we intentionally do *NOT* save back to zookeeper
    super.saveConfig()
  }

}

object ZkArgHelper {

  def basicZkClient(zkConn: String, timeout: Duration)(implicit timer: Timer) = ZkClient(zkConn, timeout).withAcl(org.apache.zookeeper.ZooDefs.Ids.OPEN_ACL_UNSAFE.asScala)

  def getArgsFromZk(zkClient: ZkClient, path: String)(implicit timer: Timer): Map[String,String] = {
    val n = zkClient(path)
    if (nodeExists(n)) {
      val childrenOp = zkClient.apply(path).getChildren
      val children = childrenOp.apply().apply()
      val childToData = children.children.map{child =>
        child.name -> new String(child.getData.apply().apply().bytes)
      }.toMap
      zkClient.release().apply()
      childToData
    } else {
      Map()
    }
  }

  def saveArgsToZk(zkClient: ZkClient, path: String, args: Map[String,String])(implicit timer: Timer) {
    val node = zkClient.apply(path)
    //first, remove this node, to clear any properties previously set
    if (nodeExists(node))
      deleteRecursively(node)

    //now recreate the node, and its children w/ all the values
    node.create().apply()
    args.foreach{case(k,v) =>
      node.create(child=Some(k), data = v.getBytes).apply()
    }
  }

  def nodeExists(node: ZNode): Boolean = {
    //there has got to be a better way ...
    try {
      node.exists.apply().apply().stat != null
    } catch {
      case ex: Exception => false
    }
  }

  def deleteRecursively(node: ZNode) {
    node.getChildren()().children.foreach{child =>
      deleteRecursively(child)
    }
    node.delete()()
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy