Java tutorial
/* * 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; } }