package guang.crawler.connector;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.Transaction;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
/**
* 连接Zookeeper的连接器
*
* @author sun
*
*/
public class ZookeeperConnector {
/**
* 底层的Zookeeper连接
*/
private ZooKeeper zookeeper;
public ZookeeperConnector(final String connectString) throws IOException {
this.zookeeper = new ZooKeeper(connectString, 3000, null);
}
/**
* 检查某个节点是否存在,如果不存在,那么创建该节点.
*
* @param path
* @param createMode
* @param data
* @return
* @throws InterruptedException
*/
public String checkAndCreateNode(final String path,
final CreateMode createMode, final byte[] data)
throws InterruptedException {
boolean exists = false;
if ((createMode == CreateMode.EPHEMERAL)
|| (createMode == CreateMode.PERSISTENT)) {
try {
exists = this.isNodeExists(path);
} catch (KeeperException e) {
e.printStackTrace();
}
}
if (!exists) {
String realPath = this.createNode(path, createMode, data);
return realPath;
}
return path;
}
/**
* 创建一个节点
*
* @param path
* @param createMode
* @param data
* @return
* @throws InterruptedException
*/
public String createNode(final String path, final CreateMode createMode,
final byte[] data) throws InterruptedException {
try {
String realPath = this.zookeeper.create(path, data,
Ids.OPEN_ACL_UNSAFE,
createMode);
return realPath;
} catch (KeeperException e) {
return null;
}
}
/**
* 如果该节点不存在,那么创建该节点,否则更新节点的数据.
*
* @param path
* @param data
* @param createMode
* @param transaction
* @return
* @throws InterruptedException
*/
public boolean createOrUpdate(final String path, final byte[] data,
final CreateMode createMode, final Transaction transaction)
throws InterruptedException {
if (transaction == null) {
boolean nodeExists = true;
try {
this.zookeeper.setData(path, data, -1);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
nodeExists = false;
} else {
e.printStackTrace();
}
}
if (!nodeExists) {
try {
this.zookeeper.create(path, data, Ids.OPEN_ACL_UNSAFE,
createMode);
} catch (KeeperException e1) {
return false;
}
}
return true;
} else {
transaction.delete(path, -1);
transaction.create(path, data, Ids.OPEN_ACL_UNSAFE, createMode);
return true;
}
}
/**
* 获取某个节点的所有子节点名称
*
* @param path
* @return
* @throws InterruptedException
*/
public List<String> getChildren(final String path)
throws InterruptedException {
try {
return this.zookeeper.getChildren(path, false);
} catch (KeeperException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取某个节点的数据内容.
*
* @param path
* @return
* @throws InterruptedException
*/
public byte[] getData(final String path) throws InterruptedException {
try {
Stat exists = this.zookeeper.exists(path, false);
if (exists != null) {
byte[] data = this.zookeeper.getData(path, false, null);
return data;
}
return null;
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
* 检查某个节点是否存在.
*
* @param path
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public boolean isNodeExists(final String path) throws KeeperException,
InterruptedException {
boolean nodeExists = false;
Stat status = this.zookeeper.exists(path, null);
nodeExists = (status != null);
return nodeExists;
}
/**
* 将某个节点递归的移动到另外一个节点.
*
* @param fromPath
* @param toPath
* @throws KeeperException
* @throws InterruptedException
*/
public void moveTo(final String fromPath, final String toPath)
throws KeeperException, InterruptedException {
Transaction transaction = this.zookeeper.transaction();
LinkedList<String> mvPath = new LinkedList<String>();
mvPath.add("");
while (!mvPath.isEmpty()) {
String first = mvPath.removeFirst();
String path = fromPath + first;
byte[] data = this.zookeeper.getData(path, false, null);
transaction.create(toPath, data, Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
List<String> children = this.zookeeper.getChildren(path, false);
if ((children != null) && (children.size() > 0)) {
for (String child : children) {
mvPath.add(first + "/" + child);
}
}
}
this.recursiveDelete(fromPath, transaction);
transaction.commit();
}
/**
* 递归的删除某个节点.
*
* @param path
* @param transaction
* @return
* @throws InterruptedException
*/
public boolean recursiveDelete(final String path,
final Transaction transaction) throws InterruptedException {
try {
List<String> children = this.zookeeper.getChildren(path, false);
if (children.size() == 0) {
this.simpleDelete(path, transaction);
return true;
} else {
boolean success = true;
for (String child : children) {
success = this.recursiveDelete(path + "/" + child,
transaction);
if (!success) {
return false;
}
}
this.simpleDelete(path, transaction);
return true;
}
} catch (KeeperException e) {
return false;
}
}
/**
* 关闭连接
*
* @throws InterruptedException
*/
public void shutdown() throws InterruptedException {
this.zookeeper.close();
}
/**
* 简单的删除,而不是递归的删除某个节点.
*
* @param path
* @param transaction
* @return
* @throws InterruptedException
*/
public boolean simpleDelete(final String path, final Transaction transaction)
throws InterruptedException {
try {
if (transaction != null) {
transaction.delete(path, -1);
} else {
this.zookeeper.delete(path, -1);
}
return true;
} catch (KeeperException e) {
e.printStackTrace();
return false;
}
}
/**
* 创建一个事务.
*
* @return
*/
public Transaction transaction() {
return this.zookeeper.transaction();
}
/**
* 更新某个节点的数据,该节点必须存在.
*
* @param path
* @param data
* @throws KeeperException
* @throws InterruptedException
*/
public void updateData(final String path, final byte[] data)
throws KeeperException, InterruptedException {
this.zookeeper.setData(path, data, -1);
}
/**
* 监听某个节点的子节点发生的变化.需要注意的是,该节点自身发生的变化是监控不到的.
*
* @param path
* @param watcher
* @throws KeeperException
* @throws InterruptedException
*/
public void watchChildren(final String path, final Watcher watcher)
throws KeeperException, InterruptedException {
this.zookeeper.getChildren(path, watcher);
}
/**
* 监控当前节点发生的变化.需要注意的是,当前节点的子节点发生的变化并不会被监控到.
*
* @param path
* @param watcher
* @throws KeeperException
* @throws InterruptedException
*/
public void watchNode(final String path, final Watcher watcher)
throws KeeperException, InterruptedException {
this.zookeeper.exists(path, watcher);
}
}