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

nirvana.support.services.ZkChildrenSupport.scala Maven / Gradle / Ivy

// Copyright 2014 Jun Tsai. All rights reserved.
// site: http://www.ganshane.com
package nirvana.support.services

import java.util.concurrent.{CopyOnWriteArraySet, ConcurrentHashMap}
import collection.JavaConversions._
import org.apache.zookeeper.WatchedEvent
import org.apache.zookeeper.KeeperException.NoNodeException
import org.apache.zookeeper.Watcher.Event.EventType
import org.apache.curator.framework.api.CuratorWatcher

/**
 * zk children support
 */
trait ZkChildrenSupport {
  this:ZkClientSupport
    with ZkPathCreatorSupport
    with ZkDeletePathSupport
    with ZkNodeDataSupport
    with RunInNoExceptionThrown
    with LoggerSupport =>
  //过滤掉针对children的重复监听
  private case class ChildrenWatcherList(internalWatcher:CuratorWatcher,watchers:CopyOnWriteArraySet[ChildrenDataWatcher])

  /**
   * 子节点观察的监听者,当父节点本身被删除,然后被创建,那么此watcher仍然有效
   */
  private final val childrenWatcher= new ConcurrentHashMap[String,ChildrenWatcherList]()
  private final val failedChildrenWatcher = new CopyOnWriteArraySet[String]()

  protected def retryFailedChildrenWatcher(){
    logger.info("retry to watch children")
    val it = failedChildrenWatcher.iterator()
    while(it.hasNext){
      val path = it.next()
      val watcherList = childrenWatcher.get(path)
      val data = internalWatchChildren(path,watcherList.internalWatcher)
      //针对每个watcher调用数据,进行执行
      if (data != null)
        watcherList.watchers.foreach(x=>runInNotExceptionThrown{x.handleDataChanged(data)})
    }
  }
  private def internalWatchChildren(path:String,curatorWatcher:CuratorWatcher):Seq[String]={
    try {
      failedChildrenWatcher.remove(path)
      val data = zkClient.getChildren.usingWatcher(curatorWatcher).forPath(path)
      data.toSeq
    }catch{
      case e:Throwable =>
        logger.warn("fail to watch node data,will retry,msg:{}",e.getMessage)
        failedChildrenWatcher.add(path)
        return null
    }
  }
  def deleteRecursive(path:String){
    val children = getChildren(path)
    for (node <- children) {
      deleteRecursive(path + '/' + node)
    }
    delete(path)
  }
  def getChildren(path:String):Seq[String]={
    try {
      zkClient.getChildren.forPath(path).toSeq
    }catch{
      case ex:NoNodeException =>
        Seq[String]()
    }
  }

  private val childrenCuratorWatcher = new CuratorWatcher {
    def process(event: WatchedEvent) {
      if(event.getPath == null) return
      val selfWatchers = childrenWatcher.get(event.getPath)
      if (selfWatchers == null) return
      event.getType match{
        case EventType.NodeChildrenChanged | EventType.NodeCreated =>
          val data = internalWatchChildren(event.getPath,this)
          selfWatchers.watchers.foreach(x=>runInNotExceptionThrown{x.handleDataChanged(data)})
        case EventType.NodeDeleted =>
          zkClient.checkExists().usingWatcher(this).forPath(event.getPath)
        case other =>
          logger.debug("other event:{}",other)
      }
    }
  }
  def watchChildren(path:String,watcher:ChildrenDataWatcher){
    var isHandleData = false
    var watchers = childrenWatcher.get(path)
    try{
      if (watchers == null){
        val arrayList = ChildrenWatcherList(childrenCuratorWatcher,new  CopyOnWriteArraySet[ChildrenDataWatcher]())
        watchers = childrenWatcher.putIfAbsent(path,arrayList)
        if (watchers == null){//说明首次添加,需要进行watcher
          watchers = arrayList
          //如果不存在此节点
          val nodeStat = stat(path)
          isHandleData = true
          nodeStat match{
            case Some(s)=> //存在此节点
              //val seq = zkClient.getChildren.usingWatcher(arrayList.internalWatcher).forPath(path).toSeq
              val seq = internalWatchChildren(path,childrenCuratorWatcher)
              runInNotExceptionThrown{ watcher.handleDataChanged(seq)}
            case None =>
              //check exists
              zkClient.checkExists().usingWatcher(arrayList.internalWatcher).forPath(path)
              runInNotExceptionThrown{ watcher.handleDataChanged(Seq[String]())}
          }
        }
      }
      if (!isHandleData)
        runInNotExceptionThrown{ watcher.handleDataChanged(getChildren(path))}
    }catch{
      case e:Throwable =>
        failedChildrenWatcher.add(path)
        logger.error("fail to watch childre,will retry "+e.getMessage)
    }
    finally{
      if (watchers != null)
        watchers.watchers.add(watcher)
    }
  }
  protected def rewatchChildren{
    //对子节点监测
    childrenWatcher.foreach{
      case (k,v) =>{
        val data = internalWatchChildren(k,v.internalWatcher)
        //针对每个watcher调用数据,进行执行
        if (data != null)
          v.watchers.foreach(x=>runInNotExceptionThrown{x.handleDataChanged(data)})
      }
    }
  }
}
/**
 * 针对子节点数据的查看器
 */
trait ChildrenDataWatcher{
  /**
   * 针对数据发变化的处理
   * @param data 子节点数据
   */
  def handleDataChanged(data:Seq[String])
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy