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

monad.rpc.internal.RpcServerFinderWithZk.scala Maven / Gradle / Ivy

The newest version!
// Copyright 2014,2015 the original author or authors. All rights reserved.
// site: http://www.ganshane.com
package monad.rpc.internal

import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.locks.ReentrantLock

import monad.rpc.model.RpcServerLocation
import monad.rpc.services.{MonadRpcErrorCode, RpcServerFinder}
import monad.support.services.{ChildrenDataWatcher, LoggerSupport, MonadException, ZookeeperTemplate}
import org.apache.tapestry5.json.JSONObject

/**
 * implements server finder
 * TODO offline or cache the server info
 */
class RpcServerFinderWithZk(zk: ZookeeperTemplate) extends RpcServerFinder with LoggerSupport {
  private val servicesCache = new ConcurrentHashMap[String, Set[RpcServerLocation]]()
  private val lock = new ReentrantLock()

  /**
   * 查找多个服务器,以pathPrefix开头
   * @param pathPrefix 路径开头
   * @return 服务器地址
   */
  override def findMulti(pathPrefix: String): Array[RpcServerLocation] = {
    var seq = servicesCache.get(pathPrefix)
    if (seq == null) {
      try {
        lock.lock()
        seq = servicesCache.get(pathPrefix)
        if (seq == null) {
          val children = zk.getChildren(pathPrefix)
          processChildren(pathPrefix, children)

          zk.watchChildren(pathPrefix,
            new ChildrenDataWatcher {
              def handleDataChanged(data: Seq[String]) {
                processChildren(pathPrefix, data)
                info("latest service locations:{} for service [{}]", servicesCache.get(pathPrefix), pathPrefix)
              }
            })

          seq = servicesCache.get(pathPrefix)
        }
      } finally {
        lock.unlock()
      }
    }

    if (seq.isEmpty) {
      throw new MonadException("server not found :%s".format(pathPrefix), MonadRpcErrorCode.SERVER_NOT_FOUND)
    }

    seq.toArray
  }

  private def processChildren(pathPrefix: String, data: Seq[String]): Unit = {
    val locations = data.flatMap { child =>
      val serverPath = pathPrefix + "/" + child
      find(serverPath)
    }
    info("latest service locations:{} for service [{}]", locations, pathPrefix)
    servicesCache.put(pathPrefix, locations.toSet)
  }

  override def find(path: String): Option[RpcServerLocation] = {
    val strOpt = zk.getDataAsString(path)
    strOpt match {
      case Some(str) =>
        Some(RpcServerLocation.fromJSON(new JSONObject(str)))
      case None =>
        None
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy