com.api6.zkclient.watcher.ZKWatcherProcess.java Source code

Java tutorial

Introduction

Here is the source code for com.api6.zkclient.watcher.ZKWatcherProcess.java

Source

/**
 *Copyright 2016 zhaojie
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */
package com.api6.zkclient.watcher;

import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

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

import com.api6.zkclient.ZKClient;
import com.api6.zkclient.event.ZKEvent;
import com.api6.zkclient.event.ZKEventThreadPool;
import com.api6.zkclient.exception.ZKNoNodeException;
import com.api6.zkclient.listener.ZKChildDataListener;
import com.api6.zkclient.listener.ZKListener;
import com.api6.zkclient.listener.ZKNodeListener;
import com.api6.zkclient.listener.ZKStateListener;

/**
 * ???
 * @author: zhaojie/zh_jie@163.com.com 
 */
public class ZKWatcherProcess {
    private static Logger LOG = LoggerFactory.getLogger(ZKWatcherProcess.class);
    private final ZKEventThreadPool eventThreadPool;
    private final ZKClient client;

    public ZKWatcherProcess(ZKClient zkClient) {
        this.client = zkClient;
        //?
        eventThreadPool = new ZKEventThreadPool(zkClient.getEventThreadPoolSize());
    }

    /**
     * ??
     * @return void
     */
    public void stop() {
        eventThreadPool.destory();
    }

    public void processStateChanged(WatchedEvent event) {
        final KeeperState keeperState = event.getState();
        LOG.info("ZooKeeper state is changed [" + keeperState + "] .");

        //?ZooKeeper?
        client.setCurrentState(keeperState);
        if (client.getShutdownTrigger()) {
            return;
        }
        //??
        Set<ZKStateListener> listeners = client.getStateListenerSet();

        //???
        for (final ZKStateListener stateListener : listeners) {
            eventThreadPool.submit(new ZKEvent("State changed to " + keeperState + " sent to " + stateListener) {
                @Override
                public void run() throws Exception {
                    stateListener.handleStateChanged(keeperState);
                }
            });
        }

        //????
        if (event.getState() == KeeperState.Expired) {
            try {
                //??
                client.reconnect();
                //??
                for (final ZKStateListener stateListener : listeners) {
                    ZKEvent zkEvent = new ZKEvent("New session event sent to " + stateListener) {
                        @Override
                        public void run() throws Exception {
                            stateListener.handleNewSession();
                        }
                    };
                    eventThreadPool.submit(zkEvent);
                }
            } catch (final Exception e) {
                LOG.info("Unable to re-establish connection. Notifying consumer of the following exception: ", e);
                //????
                for (final ZKStateListener stateListener : listeners) {
                    eventThreadPool
                            .submit(new ZKEvent("Session establishment error[" + e + "] sent to " + stateListener) {
                                @Override
                                public void run() throws Exception {
                                    stateListener.handleSessionError(e);
                                }
                            });
                }
            }
        }
    }

    /**
     * ???
     * @param event 
     * @return void
     */
    public void processChildChanged(final WatchedEvent event) {
        final String path = event.getPath();
        final Set<ZKListener> listeners = client.getChildListenerMap().get(path);
        //????
        submitChildEvent(listeners, path, event.getType());
    }

    /**
     * ???
     * @param event 
     * @return void
     */
    public void processNodeChanged(final WatchedEvent event) {
        final String path = event.getPath();
        final EventType eventType = event.getType();
        final Set<ZKListener> listeners = client.getNodeListenerMap().get(path);
        if (listeners == null || listeners.isEmpty()) {
            return;
        }

        //listenersZKChildDataListener?
        //??????
        //????ZKChildDataListener
        final Set<ZKListener> childDataChangeListners = new CopyOnWriteArraySet<>();
        final Set<ZKListener> nodeListners = new CopyOnWriteArraySet<>();

        classifyListeners(listeners, nodeListners, childDataChangeListners);

        //????
        submitNodeEvent(nodeListners, childDataChangeListners, path, eventType);

        //????
        if (eventType == EventType.NodeDataChanged) {
            //????
            submitChildDataEvent(childDataChangeListners, path, eventType);
        }
    }

    /**
     * ????
     * ????watch
     * ????????
     * ??????????
     * @param eventType 
     * @return void
     * @author: zhaojie/zh_jie@163.com 
     */
    public void processAllNodeAndChildListeners(final WatchedEvent event) {
        LOG.debug("processAllNodeAndChildListeners....");
        //???
        for (Entry<String, CopyOnWriteArraySet<ZKListener>> entry : client.getNodeListenerMap().entrySet()) {
            Set<ZKListener> nodeListners = new CopyOnWriteArraySet<ZKListener>();
            Set<ZKListener> childDataChangeListners = new CopyOnWriteArraySet<ZKListener>();
            Set<ZKListener> listeners = entry.getValue();

            classifyListeners(listeners, nodeListners, childDataChangeListners);
            //????
            submitNodeEvent(nodeListners, childDataChangeListners, entry.getKey(), event.getType());
        }
        //???
        for (Entry<String, CopyOnWriteArraySet<ZKListener>> entry : client.getChildListenerMap().entrySet()) {
            //????
            submitChildEvent(entry.getValue(), entry.getKey(), event.getType());
        }
    }

    /**
     * listeners?{@link ZKNodeListener}nodeListeners{@link ZKChildDataListener} childDataChangeListeners
     * @param listeners
     * @param nodeListeners
     * @param childDataChangeListeners 
     * @return void
     */
    private void classifyListeners(Set<ZKListener> listeners, Set<ZKListener> nodeListeners,
            Set<ZKListener> childDataChangeListeners) {
        for (ZKListener listener : listeners) {
            if (listener instanceof ZKChildDataListener) {
                if (!childDataChangeListeners.contains(listener)) {
                    childDataChangeListeners.add(listener);
                }
            } else {
                if (!nodeListeners.contains(listener)) {
                    nodeListeners.add(listener);
                }
            }
        }
    }

    /**
     * ????
     * @param listeners
     * @param childDataChangeListners
     * @param path
     * @param eventType 
     * @return void
     */
    private void submitNodeEvent(final Set<ZKListener> listeners, final Set<ZKListener> childDataChangeListners,
            final String path, final EventType eventType) {
        if (listeners != null && !listeners.isEmpty()) {
            for (final ZKListener listener : listeners) {
                ZKEvent zkEvent = new ZKEvent("Node of " + path + " changed sent to " + listener) {
                    @Override
                    public void run() throws Exception {
                        //zookeeper ????
                        LOG.debug("Rewatch the path [" + path + "] by exists method");
                        boolean flag = client.exists(path, true);
                        LOG.debug("Rewatched the path [" + path + "] by exists method");
                        try {
                            LOG.debug("Rewatch and get changed data [path:" + path + " | EventType:" + eventType
                                    + "] by getData method");
                            Object data = client.getData(path, null);
                            LOG.debug("Rewatched and return data   [" + path + " | " + data + " | EventType:"
                                    + eventType + "] by getData method");
                            listener.handle(path, eventType, data);

                            //???????
                            //?
                            if (eventType == EventType.NodeDeleted && flag) {
                                listener.handle(path, EventType.NodeCreated, data);
                            }
                        } catch (ZKNoNodeException e) {
                            //??ZKChildDataListener?
                            client.unlistenNodeChanges(path, childDataChangeListners);
                            //?client.getData(path,null)
                            listener.handle(path, eventType, null);

                            //??????
                            //?????
                            //??
                            if (eventType == EventType.NodeCreated && !flag) {
                                listener.handle(path, EventType.NodeDeleted, null);
                            }
                        }
                    }
                };
                eventThreadPool.submit(zkEvent);
            }
        }

    }

    /**
     * ?????
     * @param listeners
     * @param path
     * @param eventType 
     * @return void
     */
    private void submitChildEvent(final Set<ZKListener> listeners, final String path, final EventType eventType) {
        if (listeners != null && !listeners.isEmpty()) {
            try {
                for (final ZKListener listener : listeners) {
                    //?
                    ZKEvent zkEvent = new ZKEvent("Children of " + path + " changed sent to " + listener) {
                        @Override
                        public void run() throws Exception {
                            //zookeeper ?????
                            LOG.debug("Rewatch the path [" + path + "] by exists method");
                            client.exists(path);
                            LOG.debug("Rewatched the path [" + path + "] by exists method");
                            try {

                                LOG.debug("Rewatch and get chilldren [path:" + path + " | EventType:" + eventType
                                        + "] by getChildren method");
                                //??????
                                List<String> children = client.getChildren(path);
                                LOG.debug("Rewatched and return children  [children:" + children + " | EventType:"
                                        + eventType + "] by getChildren method");
                                //????pathZKChildDataListener
                                //??????
                                client.listenNewChildPathWithData(path, children);
                                listener.handle(path, eventType, children);
                            } catch (ZKNoNodeException e) {
                                //?client.getChildren(path)
                                listener.handle(path, eventType, null);
                            }
                        }
                    };
                    eventThreadPool.submit(zkEvent);
                }
            } catch (Exception e) {
                LOG.error("Failed to fire child changed event. Unable to getChildren.  ", e);
            }
        }
    }

    /**
     * ??????
     * @param listeners
     * @param path
     * @param eventType 
     * @return void
     */
    private void submitChildDataEvent(final Set<ZKListener> listeners, final String path,
            final EventType eventType) {
        if (listeners != null && !listeners.isEmpty()) {
            for (final ZKListener listener : listeners) {
                ZKEvent zkEvent = new ZKEvent("Children of " + path + " changed sent to " + listener) {
                    @Override
                    public void run() throws Exception {
                        //zookeeper ????
                        LOG.debug("rewatch the path [" + path + "]");
                        client.exists(path, true);
                        LOG.debug("rewatched the path [" + path + "]");
                        try {
                            LOG.debug("Try to get child changed data  [path:" + path + " | EventType:" + eventType
                                    + "]");
                            //??????
                            //?????
                            //???
                            Object data = client.getData(path, null);
                            LOG.debug("Child changed data is  [path:" + path + " | data:" + data + " | EventType:"
                                    + eventType + "]");
                            listener.handle(path, eventType, data);
                        } catch (ZKNoNodeException e) {
                            //ignore
                        }
                    }
                };
                eventThreadPool.submit(zkEvent);
            }
        }
    }
}