package com.autonavi.tinfo.t1.traffic.pub.openlr.util;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.zkclient.IZkChildListener;
import com.github.zkclient.IZkStateListener;
import com.github.zkclient.ZkClient;

public class StatusMonitor {

    private Lock lock = new ReentrantLock();// 锁对象
    private boolean usingHA = true;
    private volatile boolean isLeader = false;

    private static final Logger logger = LoggerFactory.getLogger(StatusMonitor.class);
    // 超时时间
    private int zkSessionTimeOut=5000;
    private int zkConnectionTimeOut=5000;
    //private int SESSION_TIMEOUT = 5000;
    //private int CONNECTION_TIMEOUT = 5000;

    // zookeeper server列表
    private String zkServerList = "10.17.132.71:2181";

    private String zkServerDir = "fast-update";
    private String subNode = "openlr";

    // 当前client创建的子节点
    private String curPath;
    private ZkClient zkClient;
    ScheduledExecutorService intervalMonitorExecutor = Executors.newSingleThreadScheduledExecutor();

    /**
     * 连接zookeeper
     */
    public void init() {
        logger.info("StatusMonitor.init zkSessionTimeOut:{},zkConnectionTimeOut:{}",zkSessionTimeOut,zkConnectionTimeOut);
        try {
            connect();
        } catch (Exception e) {
            this.isLeader = false;
            logger.error(e.getMessage(), e);
            try {
                connect();
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
                logger.error("error occurs during sync data from zk");
                System.exit(0);
            } finally {
                ;
            }
        }

        intervalMonitorExecutor.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                lock.lock();
                try {
                    if (zkClient == null) {
                        isLeader = false;
                        return;
                    }
                    if (zkClient != null && zkClient.getZooKeeper() == null) {
                        isLeader = false;
                        return;
                    }
                    if (zkClient != null && (!zkClient.getZooKeeper().getState().isAlive()
                            || !zkClient.getZooKeeper().getState().isConnected())) {
                        isLeader = false;
                        return;
                    }
                } finally {
                    lock.unlock();
                }
            }
        }, 0, 2, TimeUnit.SECONDS);

    }

    public void connect() throws Exception {
        if (!usingHA) {
            return;
        }

        if (this.zkClient != null) {
            this.zkClient.close();
        }
        this.zkClient = new ZkClient(zkServerList, zkSessionTimeOut, zkConnectionTimeOut);

        if (!zkClient.exists("/" + zkServerDir)) {
            zkClient.createPersistent("/" + zkServerDir, null);
        }
        if (curPath == null) {
            curPath = zkClient.createEphemeralSequential("/" + zkServerDir + "/" + subNode, "monitor".getBytes());
        }

        try {
            startWatchingTopicStatus();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            logger.error(e.getMessage(), e);
            logger.error("error occurs during sync data from zk");
            System.exit(0);
        }
        Thread.sleep(2000);// */
        handleMonitorNodeChange();
    }

    public void startWatchingTopicStatus() {
        ZkTopicStatusListener topicEventListener = new ZkTopicStatusListener();
        ZkConnectedStatusListener connectedStatusListener = new ZkConnectedStatusListener();
        try {
            zkClient.subscribeChildChanges("/" + zkServerDir, topicEventListener);
            zkClient.subscribeStateChanges(connectedStatusListener);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            startWatchingTopicStatus();
        }

    }

    public void stop() {
        if (zkClient == null) {
            logger.warn("shutdown topic event watcher");
            return;
        }
        // stopWatchingTopicEvents();
        zkClient.close();
        zkClient = null;
    }

    private void beLeader() {
        logger.info("this node gains lock {} and becomes leader ", curPath);
        System.out.println("this node gains lock " + curPath + " and becomes leader");
        this.isLeader = true;
    }

    public void setUsingHA(boolean isUsingHA) {
        this.usingHA = isUsingHA;
    }

    public void setZkServerDir(String zkServerDir) {
        this.zkServerDir = zkServerDir;
    }

    public boolean isUsingHA() {
        return usingHA;
    }

    public boolean isLeader() {
        return isLeader;
    }

    public void setZkServerList(String zkServerList) {
        this.zkServerList = zkServerList;
    }

    /*public int getSESSION_TIMEOUT() {
        return SESSION_TIMEOUT;
    }

    public void setSESSION_TIMEOUT(int sESSION_TIMEOUT) {
        SESSION_TIMEOUT = sESSION_TIMEOUT;
    }

    public int getCONNECTION_TIMEOUT() {
        return CONNECTION_TIMEOUT;
    }

    public void setCONNECTION_TIMEOUT(int cONNECTION_TIMEOUT) {
        CONNECTION_TIMEOUT = cONNECTION_TIMEOUT;
    }*/

    public int getZkSessionTimeOut() {
        return zkSessionTimeOut;
    }

    public void setZkSessionTimeOut(int zkSessionTimeOut) {
        this.zkSessionTimeOut = zkSessionTimeOut;
    }

    public int getZkConnectionTimeOut() {
        return zkConnectionTimeOut;
    }

    public void setZkConnectionTimeOut(int zkConnectionTimeOut) {
        this.zkConnectionTimeOut = zkConnectionTimeOut;
    }

    public void handleMonitorNodeChange() throws Exception {
        this.lock.lock();
        try {
            if (zkClient == null)
                return;
            if (!zkClient.exists("/" + zkServerDir)) {
                zkClient.createPersistent("/" + zkServerDir, null);
            }

            // 确认curPath是否真的是列表中的最小节点
            List<String> childs = zkClient.getChildren("/" + zkServerDir);
            if (childs == null || childs.size() == 0) {
                // 创建子节点
                curPath = zkClient.createEphemeralSequential("/" + zkServerDir + "/" + subNode, "monitor".getBytes());
                childs = zkClient.getChildren("/" + zkServerDir);
            }
            Collections.sort(childs);

            String thisNode = curPath.substring(("/" + zkServerDir + "/").length());
            int index = childs.indexOf(thisNode);
            if (index < 0) {
                curPath = zkClient.createEphemeralSequential("/" + zkServerDir + "/" + subNode, "monitor".getBytes());
                childs = zkClient.getChildren("/" + zkServerDir);
                Collections.sort(childs);
                thisNode = curPath.substring(("/" + zkServerDir + "/").length());
                index = childs.indexOf(thisNode);
            }

            if (index == 0) {
                // 确实是最小节点
                beLeader();
            } else {
                this.isLeader = false;
            }
        } finally {
            this.lock.unlock();
        }
    }

    class ZkTopicStatusListener implements IZkChildListener {

        @Override
        public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
            handleMonitorNodeChange();
        }
    }

    class ZkConnectedStatusListener implements IZkStateListener {

        @Override
        public void handleStateChanged(KeeperState state) throws Exception {
            // TODO Auto-generated method stub
            if (state.equals(state.SyncConnected) || state.equals(state.ConnectedReadOnly)) {
                System.out.println("zookeeper start to be connected");
                handleMonitorNodeChange();
            }
        }

        @Override
        public void handleNewSession() throws Exception {
            // TODO Auto-generated method stub
        }

    }

    public static void main(String[] args) throws Exception {
        StatusMonitor statusMonitor = new StatusMonitor();
        statusMonitor.setZkServerList("10.61.97.23:2181");
        statusMonitor.setUsingHA(true);

        statusMonitor.init();

        Thread.sleep(100000000);
    }

}

posted on 2016-06-20 19:54  xuxu_dragon  阅读(290)  评论(0编辑  收藏  举报