2015-01-18 00:46:28 +00:00
|
|
|
package com.github.lookout.verspaetung.zk
|
|
|
|
|
2015-01-19 18:10:28 +00:00
|
|
|
import com.github.lookout.verspaetung.TopicPartition
|
2015-01-18 18:25:04 +00:00
|
|
|
|
2015-01-18 00:46:28 +00:00
|
|
|
import org.apache.curator.framework.CuratorFramework
|
|
|
|
import org.apache.curator.framework.recipes.cache.ChildData
|
|
|
|
import org.apache.curator.framework.recipes.cache.TreeCacheListener
|
|
|
|
import org.apache.curator.framework.recipes.cache.TreeCacheEvent
|
|
|
|
|
|
|
|
/**
|
|
|
|
* AbstractTreeWatcher defines the contract and base components for the various
|
|
|
|
* Zookeeper tree watchers Verspaetung needs. The responsibility of these
|
|
|
|
* watchers is to process events from the TreeCache and emit processed events
|
|
|
|
* further down the pipeline
|
|
|
|
*/
|
|
|
|
abstract class AbstractTreeWatcher implements TreeCacheListener {
|
2015-01-19 21:08:01 +00:00
|
|
|
protected AbstractMap consumersMap
|
|
|
|
protected Closure onInitComplete
|
2015-01-18 18:25:04 +00:00
|
|
|
|
2015-01-19 21:08:01 +00:00
|
|
|
AbstractTreeWatcher(AbstractMap consumers) {
|
2015-01-18 18:25:04 +00:00
|
|
|
this.consumersMap = consumers
|
|
|
|
}
|
2015-01-18 00:46:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Process the ChildData associated with an event
|
|
|
|
*/
|
|
|
|
abstract ConsumerOffset processChildData(ChildData data)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Primary TreeCache event processing callback
|
|
|
|
*/
|
|
|
|
void childEvent(CuratorFramework client, TreeCacheEvent event) {
|
2015-01-19 21:08:01 +00:00
|
|
|
if (event?.type == TreeCacheEvent.Type.INITIALIZED) {
|
|
|
|
this.onInitComplete?.call()
|
|
|
|
}
|
|
|
|
|
2015-01-18 00:46:28 +00:00
|
|
|
/* bail out early if we don't care about the event */
|
|
|
|
if (!isNodeEvent(event)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsumerOffset offset = processChildData(event?.data)
|
|
|
|
|
|
|
|
if (offset != null) {
|
2015-01-18 18:25:04 +00:00
|
|
|
trackConsumerOffset(offset)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-01-19 18:10:28 +00:00
|
|
|
* Keep track of a ConsumerOffset in the consumersMap that was passed into
|
|
|
|
* this class on instantiation
|
2015-01-18 18:25:04 +00:00
|
|
|
*/
|
|
|
|
void trackConsumerOffset(ConsumerOffset offset) {
|
|
|
|
if (this.consumersMap == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-01-19 18:10:28 +00:00
|
|
|
TopicPartition key = new TopicPartition(offset.topic, offset.partition)
|
|
|
|
|
|
|
|
if (this.consumersMap.containsKey(key)) {
|
|
|
|
this.consumersMap[key] << offset
|
2015-01-18 18:25:04 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-01-19 18:10:28 +00:00
|
|
|
this.consumersMap[key] = [offset]
|
2015-01-18 00:46:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true if the TreeCacheEvent received pertains to a node event that
|
|
|
|
* we're interested in
|
|
|
|
*/
|
|
|
|
Boolean isNodeEvent(TreeCacheEvent event) {
|
|
|
|
if ((event?.type == TreeCacheEvent.Type.NODE_ADDED) ||
|
|
|
|
(event?.type == TreeCacheEvent.Type.NODE_UPDATED)) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|