com.navercorp.redis.cluster.gateway.NodeWatcher.java Source code

Java tutorial

Introduction

Here is the source code for com.navercorp.redis.cluster.gateway.NodeWatcher.java

Source

/*
 * Copyright 2015 NAVER Corp.
 *
 * 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.navercorp.redis.cluster.gateway;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author seongminwoo
 * @author jaehong.kim
 */
public class NodeWatcher implements Watcher {
    private static final String ZK_CLUSTER_PATH = "/RC/NOTIFICATION/CLUSTER";
    private static final String ZK_GATEWAY = "/GW";
    private static final String ZK_AFFINITY = "/AFFINITY";
    private static final String KEY_IP = "ip";
    private static final String KEY_PORT = "port";
    private static final String KEY_GW_ID = "gw_id";
    private static final String KEY_AFFINITY = "affinity";

    private final Logger log = LoggerFactory.getLogger(NodeWatcher.class);

    final CountDownLatch connLatcher = new CountDownLatch(1);

    private ZooKeeper zk;
    private GatewayConfig config;
    private GatewayServerData gatewayServerData;
    private ObjectMapper objectMapper = new ObjectMapper();

    public NodeWatcher(GatewayServerData gatewayServerData) {
        this.gatewayServerData = gatewayServerData;
    }

    public void setConfig(GatewayConfig config) {
        this.config = config;
    }

    public void start() throws IOException, InterruptedException, KeeperException {
        log.info("[NodeWatcher] Starting {} {}", config.getZkAddress(), buildGatewayPath());

        this.zk = new ZooKeeper(config.getZkAddress(), config.getZkSessionTimeout(), this);
        this.connLatcher.await(config.getZkConnectTimeout(), TimeUnit.MILLISECONDS); // if not yet connected to ZooKeeper, wait
    }

    String buildGatewayPath() {
        StringBuilder sb = new StringBuilder();
        sb.append(ZK_CLUSTER_PATH).append("/").append(config.getClusterName()).append(ZK_GATEWAY);
        return sb.toString();
    }

    String buildAffinityPath() {
        StringBuilder sb = new StringBuilder();
        sb.append(ZK_CLUSTER_PATH).append("/").append(config.getClusterName()).append(ZK_AFFINITY);
        return sb.toString();
    }

    public List<GatewayAddress> getGatewayAddress() throws KeeperException, InterruptedException, IOException {
        final List<GatewayAddress> addresses = new ArrayList<GatewayAddress>();
        final List<String> children = zk.getChildren(buildGatewayPath(), this);

        for (String node : children) {
            final int id = Integer.parseInt(node);
            final String path = buildGatewayPath() + "/" + node;
            final byte[] data = zk.getData(path, this, null);
            if (data == null) {
                continue;
            }
            log.debug("[NodeWatcher] Gateway info from CM. {path={}, data={}}", path, new String(data));

            try {
                Map keyMap = objectMapper.readValue(data, Map.class);
                if (keyMap.get(KEY_IP) != null && keyMap.get(KEY_PORT) != null) {
                    String ip = (String) keyMap.get(KEY_IP);
                    int port = (Integer) keyMap.get(KEY_PORT);
                    addresses.add(new GatewayAddress(id, ip + ":" + port));
                } else {
                    log.error("[NodeWatcher] Invalid gateway address. data={}", new String(data));
                }
            } catch (Exception e) {
                log.error("[NodeWatcher] Invalid gateway address format. data={}", new String(data));
            }
        }

        return addresses;
    }

    public GatewayAffinity getGatewayAffinity() throws KeeperException, InterruptedException, IOException {
        final GatewayAffinity gatewayAffinity = new GatewayAffinity();
        final String path = buildAffinityPath();
        if (zk.exists(path, false) == null) {
            log.info("[NodeWatcher] Not found affinity info {path={}}", path);
            return gatewayAffinity;
        }

        final byte[] data = zk.getData(path, this, null);
        if (data == null) {
            return gatewayAffinity;
        }
        log.debug("[NodeWatcher] Gateway affinity from CM. {path={}, data={}}", path, new String(data));

        try {
            List list = objectMapper.readValue(data, List.class);
            for (Object value : list) {
                Map jsonObject = (Map) value;
                final int id = (Integer) jsonObject.get(KEY_GW_ID);
                final String affinity = (String) jsonObject.get(KEY_AFFINITY);
                gatewayAffinity.put(id, affinity);
            }
        } catch (Exception e) {
            log.error("[NodeWatcher] Invalid gateway address format. data=" + new String(data), e);
        }

        return gatewayAffinity;
    }

    public void stop() {
        log.info("[NodeWatcher] Stop");

        if (zk == null) {
            return;
        }

        try {
            zk.close();
        } catch (InterruptedException e) {
            log.error("[NodeWatcher] Failed to zookeeper close", e);
        }
    }

    /**
     * @param event
     * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatchedEvent)
     */
    public void process(WatchedEvent event) {
        log.debug("[NodeWatcher] Zookeeper watched");
        log.info("[NodeWatcher] Event {type=" + event.getType() + ", state=" + event.getState() + ", path="
                + event.getPath() + "}");

        if (event.getType() == Event.EventType.None) {
            switch (event.getState()) {
            case SyncConnected:
                log.debug("[NodeWatcher] SyncConnected");
                this.connLatcher.countDown();
                break;
            default:

            }
        } else if (event.getType() == Event.EventType.NodeChildrenChanged) {
            log.debug("[NodeWatcher] NodeChildrenChanged");
            reloadGatewaylist();
            reloadGatewayAffinity();
        } else if (event.getType() == Event.EventType.NodeDataChanged) {
            log.debug("[NodeWatcher] NodeDataChanged");
            reloadGatewayAffinity();
        } else if (event.getType() == Event.EventType.NodeDeleted) {
            log.debug("[NodeWatcher] NodeDeleted");
        } else if (event.getType() == Event.EventType.NodeCreated) {
            log.debug("[NodeWatcher] NodeCreated");
        }
    }

    private void reloadGatewaylist() {
        log.info("[NodeWatcher] Reload gateway list");

        try {
            this.gatewayServerData.reload(getGatewayAddress());
        } catch (Exception e) {
            log.error("[NodeWatcher] Failed to reload", e);
        }
    }

    private void reloadGatewayAffinity() {
        log.info("[NodeWatcher] Reload gateway affinity");

        try {
            this.gatewayServerData.reload(getGatewayAffinity());
        } catch (Exception e) {
            log.error("[NodeWatcher] Failed to reload", e);
        }
    }
}