package com.baidu.disconf.web.innerapi.zookeeper.impl;
import java.nio.charset.Charset;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import com.baidu.disconf.core.common.constants.DisConfigTypeEnum;
import com.baidu.disconf.core.common.path.ZooPathMgr;
import com.baidu.disconf.core.common.zookeeper.ZookeeperMgr;
import com.baidu.disconf.web.innerapi.zookeeper.ZooKeeperDriver;
import com.baidu.disconf.web.service.zookeeper.config.ZooConfig;
import com.baidu.disconf.web.service.zookeeper.dto.ZkDisconfData;
import com.baidu.dsp.common.exception.RemoteException;
/**
* Created by knightliao on 15/1/14.
*/
public class ZookeeperDriverImpl implements ZooKeeperDriver, InitializingBean, DisposableBean {
protected static final Logger LOG = LoggerFactory.getLogger(ZookeeperDriverImpl.class);
@Autowired
private ZooConfig zooConfig;
//
// 是否初始化
//
private static boolean isInit = false;
/**
* 通知某个Node更新
*
* @param app
* @param env
* @param version
* @param disConfigTypeEnum
*/
@Override
public void notifyNodeUpdate(String app, String env, String version, String key, String value,
DisConfigTypeEnum disConfigTypeEnum) {
//
// 获取路径
//
String baseUrlString = ZooPathMgr.getZooBaseUrl(zooConfig.getZookeeperUrlPrefix(), app, env, version);
String path = "";
if (disConfigTypeEnum.equals(DisConfigTypeEnum.ITEM)) {
path = ZooPathMgr.getItemZooPath(baseUrlString);
} else {
path = ZooPathMgr.getFileZooPath(baseUrlString);
}
try {
path = ZooPathMgr.joinPath(path, key);
boolean isExist = ZookeeperMgr.getInstance().exists(path);
if (!isExist) {
LOG.info(path + " not exist. not update ZK.");
} else {
//
// 通知
//
ZookeeperMgr.getInstance().writePersistentUrl(path, value);
}
} catch (Exception e) {
LOG.error(e.toString(), e);
throw new RemoteException("zk.notify.error", e);
}
}
/**
* 获取分布式配置 Map
*
* @param app
* @param env
* @param version
*
* @return
*/
@Override
public Map<String, ZkDisconfData> getDisconfData(String app, String env, String version) {
String baseUrl = ZooPathMgr.getZooBaseUrl(zooConfig.getZookeeperUrlPrefix(), app, env, version);
Map<String, ZkDisconfData> fileMap = new HashMap<String, ZkDisconfData>();
try {
fileMap = getDisconfData(ZooPathMgr.getFileZooPath(baseUrl));
Map<String, ZkDisconfData> itemMap = getDisconfData(ZooPathMgr.getItemZooPath(baseUrl));
fileMap.putAll(itemMap);
} catch (KeeperException e) {
LOG.error(e.getMessage(), e);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
return fileMap;
}
/**
* 获取分布式配置 Map
*
* @param app
* @param env
* @param version
*
* @return
*/
@Override
public ZkDisconfData getDisconfData(String app, String env, String version, DisConfigTypeEnum disConfigTypeEnum,
String keyName) {
String baseUrl = ZooPathMgr.getZooBaseUrl(zooConfig.getZookeeperUrlPrefix(), app, env, version);
try {
ZookeeperMgr zooKeeperMgr = ZookeeperMgr.getInstance();
ZooKeeper zooKeeper = zooKeeperMgr.getZk();
if (disConfigTypeEnum.equals(DisConfigTypeEnum.FILE)) {
return getDisconfData(ZooPathMgr.getFileZooPath(baseUrl), keyName, zooKeeper);
} else if (disConfigTypeEnum.equals(DisConfigTypeEnum.ITEM)) {
return getDisconfData(ZooPathMgr.getItemZooPath(baseUrl), keyName, zooKeeper);
}
} catch (KeeperException e) {
LOG.error(e.getMessage(), e);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
return null;
}
/**
* 广度搜索法:搜索分布式配置对应的两层数据
*
* @return
*
* @throws InterruptedException
* @throws KeeperException
*/
private Map<String, ZkDisconfData> getDisconfData(String path) throws KeeperException, InterruptedException {
Map<String, ZkDisconfData> ret = new HashMap<String, ZkDisconfData>();
ZookeeperMgr zooKeeperMgr = ZookeeperMgr.getInstance();
ZooKeeper zooKeeper = zooKeeperMgr.getZk();
if (zooKeeper.exists(path, false) == null) {
return ret;
}
List<String> children = zooKeeper.getChildren(path, false);
for (String firstKey : children) {
ZkDisconfData zkDisconfData = getDisconfData(path, firstKey, zooKeeper);
if (zkDisconfData != null) {
ret.put(firstKey, zkDisconfData);
}
}
return ret;
}
/**
* 获取指定 配置数据
*
* @return
*
* @throws InterruptedException
* @throws KeeperException
*/
private ZkDisconfData getDisconfData(String path, String keyName, ZooKeeper zooKeeper)
throws KeeperException, InterruptedException {
String curPath = path + "/" + keyName;
if (zooKeeper.exists(curPath, false) == null) {
return null;
}
ZkDisconfData zkDisconfData = new ZkDisconfData();
zkDisconfData.setKey(keyName);
List<String> secChiList = zooKeeper.getChildren(curPath, false);
List<ZkDisconfData.ZkDisconfDataItem> zkDisconfDataItems = new ArrayList<ZkDisconfData.ZkDisconfDataItem>();
// list
for (String secKey : secChiList) {
// machine
ZkDisconfData.ZkDisconfDataItem zkDisconfDataItem = new ZkDisconfData.ZkDisconfDataItem();
zkDisconfDataItem.setMachine(secKey);
String thirdPath = curPath + "/" + secKey;
// value
byte[] data = zooKeeper.getData(thirdPath, null, null);
if (data != null) {
zkDisconfDataItem.setValue(new String(data, CHARSET));
}
// add
zkDisconfDataItems.add(zkDisconfDataItem);
}
zkDisconfData.setData(zkDisconfDataItems);
return zkDisconfData;
}
/**
* 返回groupName结点向下的所有zookeeper信息
*
* @param
*/
@Override
public List<String> getConf(String groupName) {
ZookeeperMgr zooKeeperMgr = ZookeeperMgr.getInstance();
ZooKeeper zooKeeper = zooKeeperMgr.getZk();
List<String> retList = new ArrayList<String>();
try {
getConf(zooKeeper, groupName, groupName, retList);
} catch (KeeperException e) {
LOG.error(e.getMessage(), e);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
return retList;
}
private static final Charset CHARSET = Charset.forName("UTF-8");
private void getConf(ZooKeeper zk, String groupName, String displayName, List<String> retList)
throws KeeperException, InterruptedException {
try {
StringBuffer sb = new StringBuffer();
int pathLength = StringUtils.countMatches(groupName, "/");
for (int i = 0; i < pathLength - 2; ++i) {
sb.append("\t");
}
List<String> children = zk.getChildren(groupName, false);
if (!"/".equals(groupName)) {
sb.append("|----" + displayName);
Stat stat = new Stat();
byte[] data = zk.getData(groupName, null, stat);
if (data != null && children.size() == 0) {
sb.append("\t" + new String(data, CHARSET));
}
} else {
sb.append(groupName);
}
retList.add(sb.toString());
//
//
//
Collections.sort(children, Collator.getInstance(java.util.Locale.CHINA));
for (String child : children) {
String nextName = "";
if (!"/".equals(groupName)) {
nextName = groupName + "/" + child;
} else {
nextName = groupName + "/" + child;
}
String node = StringUtils.substringAfterLast(nextName, "/");
getConf(zk, groupName + "/" + child, node, retList);
}
} catch (KeeperException.NoNodeException e) {
LOG.error("Group " + groupName + " does not exist\n");
}
}
@Override
public void destroy() throws Exception {
ZookeeperMgr.getInstance().release();
}
@Override
public synchronized void afterPropertiesSet() throws Exception {
if (!isInit) {
ZookeeperMgr.getInstance().init(zooConfig.getZooHosts(), zooConfig.getZookeeperUrlPrefix(), false);
isInit = true;
}
}
}