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

monad.face.internal.ResourcesWatcher.scala Maven / Gradle / Ivy

// Copyright 2012,2013,2015,2016 the original author or authors. All rights reserved.
// site: http://www.ganshane.com
package monad.face.internal

import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.{ConcurrentHashMap, Executors, ThreadFactory, TimeUnit}
import javax.annotation.PostConstruct

import com.lmax.disruptor.dsl.Disruptor
import com.lmax.disruptor.{EventFactory, EventTranslator}
import monad.face.CloudPathConstants
import monad.face.model.ResourceEvent.ResourceEventType
import monad.face.model.{ResourceDefinition, ResourceEvent}
import monad.face.services.{GroupZookeeperTemplate, ResourceDefinitionLoader, ResourceDefinitionLoaderListener}
import stark.utils.StarkUtilsConstants
import stark.utils.services.{ChildrenDataWatcher, NodeDataWatcher, XmlLoader}
import org.apache.tapestry5.ioc.services.{ParallelExecutor, RegistryShutdownHub}
import org.apache.tapestry5.services.Core
import org.slf4j.LoggerFactory

import scala.collection.JavaConversions._
import scala.util.control.NonFatal

/**
 * 针对资源的监控
 * @author jcai
 */
//@EagerLoad
class ResourcesWatcher(zk: GroupZookeeperTemplate,
                       @Core listener: ResourceDefinitionLoaderListener,
                       parallelExecutor: ParallelExecutor) extends ResourceDefinitionLoader {
  private val resources = new ConcurrentHashMap[String, ResourceDefinition]()
  private val logger = LoggerFactory getLogger getClass
  private val locker = new ReentrantLock()
  //针对数据的检测
  private val EVENT_FACTORY = new EventFactory[ResourceEvent] {
    def newInstance() = new ResourceEvent()
  }
  private val buffer = 1 << 2
  //单线程异步处理资源事件
  private val disruptor = new Disruptor[ResourceEvent](EVENT_FACTORY, buffer, Executors.newFixedThreadPool(1, new ThreadFactory {
    override def newThread(r: Runnable): Thread = {
      val t = new Thread(r)
      t.setDaemon(true)
      t
    }
  }))

  private[internal] var children = Seq[String]()
  private var hasClosed = false

  /**
   * 启动对象实例
   */
  @PostConstruct
  def start(hub: RegistryShutdownHub) {
    disruptor.handleEventsWith(new ResourceEventHandler(listener, zk))
    disruptor.start()
    zk.watchChildren(CloudPathConstants.RESOURCES_PATH,
      new ChildrenDataWatcher {
        def handleDataChanged(newChildren: Seq[String]) {
          try {
            locker.lock()
            //增加的节点
            newChildren.diff(children).foreach(x => watch(x, CloudPathConstants.RESOURCE_PATH_FORMAT.format(x)))
            children = newChildren
            logger.info("latest resources:[{}]", children)
          } finally {
            locker.unlock()
          }
        }
      })

    hub.addRegistryWillShutdownListener(new Runnable {
      override def run(): Unit = shutdown()
    })
  }

  /**
   * 关闭对象
   */
  def shutdown() {
    if (hasClosed)
      return
    logger.info("closing resource definition loader...")
    resources.keySet().foreach(listener.onResourceUnloaded)
    resources.clear()
    hasClosed = true
    try {
      disruptor.shutdown(2, TimeUnit.SECONDS)
    } catch {
      case NonFatal(e) =>
        disruptor.halt()
    }
  }

  private def watch(key: String, path: String) {
    logger.debug("[{}] begin to watch resource path {}", key, path)
    zk.watchNodeData(path,
      new NodeDataWatcher {
        def handleNodeDeleted() {
          logger.debug("[{}] watch delete path {}", key, path)
          removeResource(key)
        }

        def handleDataChanged(data: Option[Array[Byte]]) {
          if (data.isDefined) {
            val x = data.get
            logger.debug("[{}] watched resource path {}", key, path)
            val rd = XmlLoader.parseXML[ResourceDefinition](new String(x, StarkUtilsConstants.UTF8_ENCODING))
            val resyncStat = zk.stat(CloudPathConstants.RESOURCE_RESYNC_PATH_FORMAT.format(key))
            val stat = zk.stat(path).get
            resyncStat match {
              case Some(y) =>
                resync(rd, stat.getVersion)
              case None =>
                pushEvent(rd, ResourceEvent.Start(stat.getVersion))
            }
            resources.put(key, rd)
          }
        }
      })
  }

  def resync(rd: ResourceDefinition, version: Int) {
    removeResource(rd.name)
    pushEvent(rd, ResourceEvent.Start(version))
  }

  def removeResource(key: String) = {
    val obj = resources.remove(key)
    if (obj != null) {
      pushEvent(obj, ResourceEvent.Remove)
    }
    obj
  }

  private def pushEvent(resource: ResourceDefinition, resourceEventType: ResourceEventType) {
    disruptor.publishEvent(new EventTranslator[ResourceEvent] {
      def translateTo(event: ResourceEvent, sequence: Long) {
        event.resource = resource
        event.eventType = resourceEventType
      }
    })
  }

  def getResourceDefinitions = resources.values().iterator()

  def getResourceDefinition(name: String) = {
    val v = resources.get(name)
    if (v == null) None else Some(v)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy