io.flood.registry.zk.ZookeeperRegistry.java Source code

Java tutorial

Introduction

Here is the source code for io.flood.registry.zk.ZookeeperRegistry.java

Source

/*
 * Copyright 2015 The RPC Project
 *
 * The RPC Project licenses this file to you 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 io.flood.registry.zk;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import io.flood.common.Resource;
import io.flood.common.annotation.Config;
import io.flood.common.utils.BytesUtils;
import io.flood.common.utils.GsonFactory;
import io.flood.common.utils.PropertiesUtil;
import io.flood.registry.api.NotifyListener;
import io.flood.registry.api.Registry;
import io.flood.registry.api.RegistryAction;
import io.flood.registry.api.RegistryContants;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

@RegistryAction(value = RegistryContants.REGSIT_ZOOKEEPER, order = 0)
public class ZookeeperRegistry implements Registry {

    private static final Logger LOG = LoggerFactory.getLogger(ZookeeperRegistry.class);
    private CuratorFramework client;
    private List<NotifyListener> listeners = new CopyOnWriteArrayList<NotifyListener>();
    private final Map<String, Resource> localService = Maps.newConcurrentMap();

    @Config("flood.zookeeper")
    private String zookeeper;
    @Config("flood.bath.path")
    private String basePath;

    public ZookeeperRegistry() {

    }

    public void start() {

        if (Strings.isNullOrEmpty(zookeeper)) {
            readConfig();
        }
        final ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.newClient(zookeeper, retryPolicy);
        client.getConnectionStateListenable()
                .addListener((client, state) -> ZookeeperRegistry.this.stateChanged(state)

        );

        client.start();
    }

    private void readConfig() {

        try {
            PropertiesUtil util = PropertiesUtil.instance("flood.properties");
            zookeeper = (String) util.get("rpc.zookeeper");
            basePath = (String) util.get("rpc.path", "/flood/rpc/services");
        } catch (Exception e) {
            zookeeper = "127.0.0.1:2181";
            basePath = "/flood/rpc/services";
        }
    }

    public void createPersistent(String path) {
        try {
            client.create().forPath(path);
        } catch (KeeperException.NodeExistsException e) {
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    public void createEphemeral(String path) {
        try {
            client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
        } catch (KeeperException.NodeExistsException e) {
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    public void delete(String path) {
        try {
            client.delete().forPath(path);
        } catch (KeeperException.NoNodeException e) {
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    public List<String> getChildren(String path) {
        try {
            return client.getChildren().forPath(path);
        } catch (KeeperException.NoNodeException e) {
            return null;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    @Override
    public void register(Resource resource) {
        try {
            client.create().withMode(CreateMode.EPHEMERAL).forPath(Paths.get(resource),
                    BytesUtils.toBytes(GsonFactory.toJson(resource)));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void unregister(Resource resource) {
        try {
            client.delete().forPath(Paths.get(resource));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private void subscribeRealService(final Resource resource, final NotifyListener listener) throws Exception {
        final String resourcePath = Paths.get(resource);
        client.getChildren().usingWatcher(new CuratorWatcher() {
            @Override
            public void process(WatchedEvent event) throws Exception {
                switch (event.getType()) {
                case NodeDeleted:
                    listener.notifyResourceDeleted(resource);
                    break;
                case NodeDataChanged:
                    Resource newResource = GsonFactory.fromJson(client.getData().forPath(resourcePath),
                            Resource.class);
                    localService.replace(resourcePath, newResource);
                    listener.notifyResourceChaneged(newResource);
                }
            }
        }).forPath(resourcePath);
    }

    @Override
    public void subscribe(final String name, final String group, final NotifyListener listener) {
        try {
            String serviceDir = Paths.get(name, group);
            client.getChildren().usingWatcher(new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    switch (watchedEvent.getType()) {
                    case NodeChildrenChanged: {

                        try {
                            final List<String> nodes = client.getChildren().forPath(serviceDir);
                            List<Resource> services = Lists.newArrayListWithCapacity(nodes.size());
                            String servicePath = null;
                            for (String node : nodes) {
                                servicePath = Paths.get(name, group, node);
                                byte[] buffer = client.getData().forPath(servicePath);
                                Resource resource = GsonFactory.fromJson(buffer, Resource.class);
                                if (!localService.containsKey(servicePath)) {
                                    LOG.info("new serice {},{}", servicePath, resource);
                                    listener.notifyResourceCreated(resource);
                                    subscribeRealService(resource, listener);
                                    localService.put(servicePath, resource);
                                }
                            }

                            Maps.filterEntries(localService, entry -> {
                                if (nodes.contains(entry.getKey())) {
                                    return true;
                                }
                                listener.notifyResourceDeleted(entry.getValue());
                                return false;
                            });
                        } catch (Exception e) {
                            LOG.warn("node child changed ,but process error ", e);
                        }

                    }
                    }
                }
            }).forPath(Paths.get(name, group));
            LOG.info("subscribe {}", Paths.get(name, group));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void unsubscribe(String group, String name, NotifyListener listener) {

    }

    @Override
    public List<Resource> lookup(String group, String name) {
        return null;
    }

    void stateChanged(ConnectionState state) {

    }

    public void destroy() {
        client.close();
    }

    public String getZookeeper() {
        return zookeeper;
    }

    public void setZookeeper(String zookeeper) {
        this.zookeeper = zookeeper;
    }

    public String getBasePath() {
        return basePath;
    }

    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }
}