//package com.github.ltsopensource.core;
//
//import com.github.ltsopensource.core.cluster.Node;
//import com.github.ltsopensource.core.commons.utils.StringUtils;
//import com.github.ltsopensource.core.constant.Constants;
//import com.github.ltsopensource.core.factory.NamedThreadFactory;
//import com.github.ltsopensource.core.logger.Logger;
//import com.github.ltsopensource.core.logger.LoggerFactory;
//import com.github.ltsopensource.core.registry.FailbackRegistry;
//import com.github.ltsopensource.core.registry.NodeRegistryUtils;
//import com.github.ltsopensource.core.registry.NotifyListener;
//
//import java.io.IOException;
//import java.net.*;
//import java.util.*;
//import java.util.concurrent.*;
//
///**
// * @author Robert HG (254963746@qq.com) on 9/10/15.
// */
//public class MulticastRegistry extends FailbackRegistry {
//
// // 日志输出
// private static final Logger logger = LoggerFactory.getLogger(MulticastRegistry.class);
//
// private static final int DEFAULT_MULTICAST_PORT = 1234;
//
// private final InetAddress multicastAddress;
//
// private final MulticastSocket multicastSocket;
//
// private final int multicastPort;
//
// private final ConcurrentMap<Node, Set<Node>> received = new ConcurrentHashMap<Node, Set<Node>>();
//
// private final ScheduledExecutorService cleanExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("LTSMulticastRegistryCleanTimer", true));
//
// private final ScheduledFuture<?> cleanFuture;
//
// private final int cleanPeriod;
//
// public MulticastRegistry(Application application) {
// super(application);
//
// String address = NodeRegistryUtils.getRealRegistryAddress(application.getConfig().getRegistryAddress());
// String host = address.split(":")[0];
// Integer port = Integer.parseInt(address.split(":")[1]);
//
// if (!isMulticastAddress(host)) {
// throw new IllegalArgumentException("Invalid multicast address " + host + ", scope: 224.0.0.0 - 239.255.255.255");
// }
// try {
// multicastAddress = InetAddress.getByName(host);
// multicastPort = port <= 0 ? DEFAULT_MULTICAST_PORT : port;
// multicastSocket = new MulticastSocket(multicastPort);
// multicastSocket.setLoopbackMode(false);
// multicastSocket.joinGroup(multicastAddress);
// Thread thread = new Thread(new Runnable() {
// public void run() {
// byte[] buf = new byte[2048];
// DatagramPacket recv = new DatagramPacket(buf, buf.length);
// while (!multicastSocket.isClosed()) {
// try {
// multicastSocket.receive(recv);
// String msg = new String(recv.getData()).trim();
// int i = msg.indexOf('\n');
// if (i > 0) {
// msg = msg.substring(0, i).trim();
// }
// MulticastRegistry.this.receive(msg, (InetSocketAddress) recv.getSocketAddress());
// Arrays.fill(buf, (byte) 0);
// } catch (Throwable e) {
// if (!multicastSocket.isClosed()) {
// logger.error(e.getMessage(), e);
// }
// }
// }
// }
// }, "LTSMulticastRegistryReceiver");
// thread.setDaemon(true);
// thread.start();
// } catch (IOException e) {
// throw new IllegalStateException(e.getMessage(), e);
// }
//
// this.cleanPeriod = application.getConfig().getParameter(Constants.REDIS_SESSION_TIMEOUT, Constants.DEFAULT_SESSION_TIMEOUT);
//
// boolean admin = true;
// if (admin) {
// this.cleanFuture = cleanExecutor.scheduleWithFixedDelay(new Runnable() {
// public void run() {
// try {
// clean(); // 清除过期者
// } catch (Throwable t) { // 防御性容错
// logger.error("Unexpected exception occur at clean expired provider, cause: " + t.getMessage(), t);
// }
// }
// }, cleanPeriod, cleanPeriod, TimeUnit.MILLISECONDS);
// } else {
// this.cleanFuture = null;
// }
// }
//
// private static boolean isMulticastAddress(String ip) {
// int i = ip.indexOf('.');
// if (i > 0) {
// String prefix = ip.substring(0, i);
// if (StringUtils.isInteger(prefix)) {
// int p = Integer.parseInt(prefix);
// return p >= 224 && p <= 239;
// }
// }
// return false;
// }
//
// private void clean() {
// for (Set<Node> providers : new HashSet<Set<Node>>(received.values())) {
// for (Node node : new HashSet<Node>(providers)) {
// if (isExpired(node)) {
// if (logger.isWarnEnabled()) {
// logger.warn("Clean expired provider " + node);
// }
// doUnregister(node);
// }
// }
// }
// }
//
// private boolean isExpired(Node node) {
//
// Socket socket = null;
// try {
// socket = new Socket(node.getIp(), node.getPort());
// } catch (Throwable e) {
// try {
// Thread.sleep(100);
// } catch (Throwable ignored) {
// }
// Socket socket2 = null;
// try {
// socket2 = new Socket(node.getIp(), node.getPort());
// } catch (Throwable e2) {
// return true;
// } finally {
// if (socket2 != null) {
// try {
// socket2.close();
// } catch (Throwable ignored) {
// }
// }
// }
// } finally {
// if (socket != null) {
// try {
// socket.close();
// } catch (Throwable ignored) {
// }
// }
// }
// return false;
// }
//
// private void receive(String msg, InetSocketAddress remoteAddress) {
// if (logger.isInfoEnabled()) {
// logger.info("Receive multicast message: " + msg + " from " + remoteAddress);
// }
// if (msg.startsWith(Constants.REGISTER)) {
// URL url = URL.valueOf(msg.substring(Constants.REGISTER.length()).trim());
// registered(url);
// } else if (msg.startsWith(Constants.UNREGISTER)) {
// URL url = URL.valueOf(msg.substring(Constants.UNREGISTER.length()).trim());
// unregistered(url);
// } else if (msg.startsWith(Constants.SUBSCRIBE)) {
// URL url = URL.valueOf(msg.substring(Constants.SUBSCRIBE.length()).trim());
// Set<Node> urls = getRegistered();
// if (urls != null && urls.size() > 0) {
// for (URL u : urls) {
// if (UrlUtils.isMatch(url, u)) {
// String host = remoteAddress != null && remoteAddress.getAddress() != null
// ? remoteAddress.getAddress().getHostAddress() : url.getIp();
// broadcast(Constants.REGISTER + " " + u.toFullString());
// }
// }
// }
// }/* else if (msg.startsWith(UNSUBSCRIBE)) {
// }*/
// }
//
// private void broadcast(String msg) {
// if (logger.isInfoEnabled()) {
// logger.info("Send broadcast message: " + msg + " to " + multicastAddress + ":" + multicastPort);
// }
// try {
// byte[] data = (msg + "\n").getBytes();
// DatagramPacket hi = new DatagramPacket(data, data.length, multicastAddress, multicastPort);
// multicastSocket.send(hi);
// } catch (Exception e) {
// throw new IllegalStateException(e.getMessage(), e);
// }
// }
//
// protected void doRegister(Node node) {
// broadcast(Constants.REGISTER + " " + node.toFullString());
// }
//
// protected void doUnregister(Node node) {
// broadcast(Constants.UNREGISTER + " " + node.toFullString
//
// protected void doSubscribe(URL url, NotifyListener listener) {
// if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
// admin = true;
// }
// broadcast(Constants.SUBSCRIBE + " " + url.toFullString());
// synchronized (listener) {
// try {
// listener.wait(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
// } catch (InterruptedException ignored) {
// }
// }
// }
//
// protected void doUnsubscribe(URL url, NotifyListener listener) {
// if (!Constants.ANY_VALUE.equals(url.getServiceInterface())
// && url.getParameter(Constants.REGISTER_KEY, true)) {
// unregister(url);
// }
// broadcast(Constants.UNSUBSCRIBE + " " + url.toFullString());
// }
//
// public boolean isAvailable() {
// try {
// return multicastSocket != null;
// } catch (Throwable t) {
// return false;
// }
// }
//
// public void destroy() {
// super.destroy();
// try {
// if (cleanFuture != null) {
// cleanFuture.cancel(true);
// }
// } catch (Throwable t) {
// logger.warn(t.getMessage(), t);
// }
// try {
// multicastSocket.leaveGroup(multicastAddress);
// multicastSocket.close();
// } catch (Throwable t) {
// logger.warn(t.getMessage(), t);
// }
// }
//
// @Override
// protected void doUnRegister(Node node) {
//
// }
//
// @Override
// protected void doSubscribe(Node node, NotifyListener listener) {
//
// }
//
// @Override
// protected void doUnsubscribe(Node node, NotifyListener listener) {
//
// }
//
// protected void registered(URL url) {
// for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {
// URL key = entry.getKey();
// if (UrlUtils.isMatch(key, url)) {
// Set<URL> urls = received.get(key);
// if (urls == null) {
// received.putIfAbsent(key, new ConcurrentHashSet<URL>());
// urls = received.get(key);
// }
// urls.add(url);
// List<URL> list = toList(urls);
// for (NotifyListener listener : entry.getValue()) {
// notify(key, listener, list);
// synchronized (listener) {
// listener.notify();
// }
// }
// }
// }
// }
//
// protected void unregistered(URL url) {
// for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {
// URL key = entry.getKey();
// if (UrlUtils.isMatch(key, url)) {
// Set<URL> urls = received.get(key);
// if (urls != null) {
// urls.remove(url);
// }
// List<URL> list = toList(urls);
// for (NotifyListener listener : entry.getValue()) {
// notify(key, listener, list);
// }
// }
// }
// }
//
// protected void subscribed(URL url, NotifyListener listener) {
// List<URL> urls = lookup(url);
// notify(url, listener, urls);
// }
//
// private List<URL> toList(Set<URL> urls) {
// List<URL> list = new ArrayList<URL>();
// if (urls != null && urls.size() > 0) {
// for (URL url : urls) {
// list.add(url);
// }
// }
// return list;
// }
//
// public void register(URL url) {
// super.register(url);
// registered(url);
// }
//
// public void unregister(URL url) {
// super.unregister(url);
// unregistered(url);
// }
//
// public void subscribe(URL url, NotifyListener listener) {
// super.subscribe(url, listener);
// subscribed(url, listener);
// }
//
// public void unsubscribe(URL url, NotifyListener listener) {
// super.unsubscribe(url, listener);
// received.remove(url);
// }
//
// public List<URL> lookup(URL url) {
// List<URL> urls = new ArrayList<URL>();
// Map<String, List<URL>> notifiedUrls = getNotified().get(url);
// if (notifiedUrls != null && notifiedUrls.size() > 0) {
// for (List<URL> values : notifiedUrls.values()) {
// urls.addAll(values);
// }
// }
// if (urls == null || urls.size() == 0) {
// List<URL> cacheUrls = getCacheUrls(url);
// if (cacheUrls != null && cacheUrls.size() > 0) {
// urls.addAll(cacheUrls);
// }
// }
// if (urls == null || urls.size() == 0) {
// for (URL u : getRegistered()) {
// if (UrlUtils.isMatch(url, u)) {
// urls.add(u);
// }
// }
// }
// if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
// for (URL u : getSubscribed().keySet()) {
// if (UrlUtils.isMatch(url, u)) {
// urls.add(u);
// }
// }
// }
// return urls;
// }
//
// public MulticastSocket getMutilcastSocket() {
// return multicastSocket;
// }
//
// public Map<Node, Set<Node>> getReceived() {
// return received;
// }
//
//}