com.quancheng.saluki.core.registry.internal.FailbackRegistry.java Source code

Java tutorial

Introduction

Here is the source code for com.quancheng.saluki.core.registry.internal.FailbackRegistry.java

Source

/*
 * Copyright (c) 2016, Quancheng-ec.com All right reserved. This software is the
 * confidential and proprietary information of Quancheng-ec.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Quancheng-ec.com.
 */
package com.quancheng.saluki.core.registry.internal;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.quancheng.saluki.core.common.Constants;
import com.quancheng.saluki.core.common.GrpcURL;
import com.quancheng.saluki.core.common.NamedThreadFactory;
import com.quancheng.saluki.core.registry.NotifyListener;

/**
 * @author shimingliu 20161214 ?1:55:42
 * @version FailBackRegistry1.java, v 0.0.1 20161214 ?1:55:42 shimingliu
 */
public abstract class FailbackRegistry extends AbstractRegistry {

    // 
    private final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(1,
            new NamedThreadFactory("SalukiRegistryFailedRetryTimer", true));
    // ????
    private final ScheduledFuture<?> retryFuture;
    private final Set<GrpcURL> failedRegistered = Sets.newConcurrentHashSet();
    private final Set<GrpcURL> failedUnregistered = Sets.newConcurrentHashSet();
    private final ConcurrentMap<GrpcURL, Set<NotifyListener.NotifyServiceListener>> failedSubscribed = Maps
            .newConcurrentMap();
    private final ConcurrentMap<GrpcURL, Set<NotifyListener.NotifyServiceListener>> failedUnsubscribed = Maps
            .newConcurrentMap();
    private final ConcurrentMap<GrpcURL, Map<NotifyListener.NotifyServiceListener, List<GrpcURL>>> failedNotified = Maps
            .newConcurrentMap();

    public FailbackRegistry(GrpcURL url) {
        super(url);
        int retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY,
                Constants.DEFAULT_REGISTRY_RETRY_PERIOD);
        this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() {

            public void run() {
                // 
                try {
                    retry();
                } catch (Throwable t) { // 
                    logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
                }
            }
        }, retryPeriod, retryPeriod, TimeUnit.MILLISECONDS);
    }

    private void retry() {
        if (!failedRegistered.isEmpty()) {
            Set<GrpcURL> failed = new HashSet<GrpcURL>(failedRegistered);
            if (failed.size() > 0) {
                if (logger.isInfoEnabled()) {
                    logger.info("Retry register " + failed);
                }
                try {
                    for (GrpcURL url : failed) {
                        try {
                            doRegister(url);
                            failedRegistered.remove(url);
                        } catch (Throwable t) { // ?
                            logger.warn("Failed to retry register " + failed + ", waiting for again, cause: "
                                    + t.getMessage(), t);
                        }
                    }
                } catch (Throwable t) { // ?
                    logger.warn(
                            "Failed to retry register " + failed + ", waiting for again, cause: " + t.getMessage(),
                            t);
                }
            }
        }
        if (!failedUnregistered.isEmpty()) {
            Set<GrpcURL> failed = new HashSet<GrpcURL>(failedUnregistered);
            if (failed.size() > 0) {
                if (logger.isInfoEnabled()) {
                    logger.info("Retry unregister " + failed);
                }
                try {
                    for (GrpcURL url : failed) {
                        try {
                            doUnregister(url);
                            failedUnregistered.remove(url);
                        } catch (Throwable t) { // ?
                            logger.warn("Failed to retry unregister  " + failed + ", waiting for again, cause: "
                                    + t.getMessage(), t);
                        }
                    }
                } catch (Throwable t) { // ?
                    logger.warn("Failed to retry unregister  " + failed + ", waiting for again, cause: "
                            + t.getMessage(), t);
                }
            }
        }
        if (!failedSubscribed.isEmpty()) {
            Map<GrpcURL, Set<NotifyListener.NotifyServiceListener>> failed = new HashMap<GrpcURL, Set<NotifyListener.NotifyServiceListener>>(
                    failedSubscribed);
            for (Map.Entry<GrpcURL, Set<NotifyListener.NotifyServiceListener>> entry : new HashMap<GrpcURL, Set<NotifyListener.NotifyServiceListener>>(
                    failed).entrySet()) {
                if (entry.getValue() == null || entry.getValue().size() == 0) {
                    failed.remove(entry.getKey());
                }
            }
            if (failed.size() > 0) {
                if (logger.isInfoEnabled()) {
                    logger.info("Retry subscribe " + failed);
                }
                try {
                    for (Map.Entry<GrpcURL, Set<NotifyListener.NotifyServiceListener>> entry : failed.entrySet()) {
                        GrpcURL url = entry.getKey();
                        Set<NotifyListener.NotifyServiceListener> listeners = entry.getValue();
                        for (NotifyListener.NotifyServiceListener listener : listeners) {
                            try {
                                doSubscribe(url, listener);
                                listeners.remove(listener);
                            } catch (Throwable t) { // ?
                                logger.warn("Failed to retry subscribe " + failed + ", waiting for again, cause: "
                                        + t.getMessage(), t);
                            }
                        }
                    }
                } catch (Throwable t) { // ?
                    logger.warn(
                            "Failed to retry subscribe " + failed + ", waiting for again, cause: " + t.getMessage(),
                            t);
                }
            }
        }
        if (!failedUnsubscribed.isEmpty()) {
            Map<GrpcURL, Set<NotifyListener.NotifyServiceListener>> failed = new HashMap<GrpcURL, Set<NotifyListener.NotifyServiceListener>>(
                    failedUnsubscribed);
            for (Map.Entry<GrpcURL, Set<NotifyListener.NotifyServiceListener>> entry : new HashMap<GrpcURL, Set<NotifyListener.NotifyServiceListener>>(
                    failed).entrySet()) {
                if (entry.getValue() == null || entry.getValue().size() == 0) {
                    failed.remove(entry.getKey());
                }
            }
            if (failed.size() > 0) {
                if (logger.isInfoEnabled()) {
                    logger.info("Retry unsubscribe " + failed);
                }
                try {
                    for (Map.Entry<GrpcURL, Set<NotifyListener.NotifyServiceListener>> entry : failed.entrySet()) {
                        GrpcURL url = entry.getKey();
                        Set<NotifyListener.NotifyServiceListener> listeners = entry.getValue();
                        for (NotifyListener.NotifyServiceListener listener : listeners) {
                            try {
                                doUnsubscribe(url, listener);
                                listeners.remove(listener);
                            } catch (Throwable t) { // ?
                                logger.warn("Failed to retry unsubscribe " + failed + ", waiting for again, cause: "
                                        + t.getMessage(), t);
                            }
                        }
                    }
                } catch (Throwable t) { // ?
                    logger.warn("Failed to retry unsubscribe " + failed + ", waiting for again, cause: "
                            + t.getMessage(), t);
                }
            }
        }
        if (!failedNotified.isEmpty()) {
            Map<GrpcURL, Map<NotifyListener.NotifyServiceListener, List<GrpcURL>>> failed = new HashMap<GrpcURL, Map<NotifyListener.NotifyServiceListener, List<GrpcURL>>>(
                    failedNotified);
            for (Map.Entry<GrpcURL, Map<NotifyListener.NotifyServiceListener, List<GrpcURL>>> entry : new HashMap<GrpcURL, Map<NotifyListener.NotifyServiceListener, List<GrpcURL>>>(
                    failed).entrySet()) {
                if (entry.getValue() == null || entry.getValue().size() == 0) {
                    failed.remove(entry.getKey());
                }
            }
            if (failed.size() > 0) {
                if (logger.isInfoEnabled()) {
                    logger.info("Retry notify " + failed);
                }
                try {
                    for (Map<NotifyListener.NotifyServiceListener, List<GrpcURL>> values : failed.values()) {
                        for (Map.Entry<NotifyListener.NotifyServiceListener, List<GrpcURL>> entry : values
                                .entrySet()) {
                            try {
                                NotifyListener.NotifyServiceListener listener = entry.getKey();
                                List<GrpcURL> urls = entry.getValue();
                                listener.notify(urls);
                                values.remove(listener);
                            } catch (Throwable t) { // ?
                                logger.warn("Failed to retry notify " + failed + ", waiting for again, cause: "
                                        + t.getMessage(), t);
                            }
                        }
                    }
                } catch (Throwable t) { // ?
                    logger.warn(
                            "Failed to retry notify " + failed + ", waiting for again, cause: " + t.getMessage(),
                            t);
                }
            }
        }
    }

    public Future<?> getRetryFuture() {
        return retryFuture;
    }

    public Set<GrpcURL> getFailedRegistered() {
        return failedRegistered;
    }

    public Set<GrpcURL> getFailedUnregistered() {
        return failedUnregistered;
    }

    public Map<GrpcURL, Set<NotifyListener.NotifyServiceListener>> getFailedSubscribed() {
        return failedSubscribed;
    }

    public Map<GrpcURL, Set<NotifyListener.NotifyServiceListener>> getFailedUnsubscribed() {
        return failedUnsubscribed;
    }

    public Map<GrpcURL, Map<NotifyListener.NotifyServiceListener, List<GrpcURL>>> getFailedNotified() {
        return failedNotified;
    }

    private void addFailedSubscribed(GrpcURL url, NotifyListener.NotifyServiceListener listener) {
        Set<NotifyListener.NotifyServiceListener> listeners = failedSubscribed.get(url);
        if (listeners == null) {
            listeners = Sets.newConcurrentHashSet();
            listeners = failedSubscribed.putIfAbsent(url, listeners);
        }
        listeners.add(listener);
    }

    private void removeFailedSubscribed(GrpcURL url, NotifyListener.NotifyServiceListener listener) {
        Set<NotifyListener.NotifyServiceListener> listeners = failedSubscribed.get(url);
        if (listeners != null) {
            listeners.remove(listener);
        }
        listeners = failedUnsubscribed.get(url);
        if (listeners != null) {
            listeners.remove(listener);
        }
        Map<NotifyListener.NotifyServiceListener, List<GrpcURL>> notified = failedNotified.get(url);
        if (notified != null) {
            notified.remove(listener);
        }
    }

    @Override
    public void register(GrpcURL url) {
        super.register(url);
        failedRegistered.remove(url);
        failedUnregistered.remove(url);
        try {
            // ????
            doRegister(url);
        } catch (Exception e) {
            logger.error("Failed to uregister " + url + ", waiting for retry, cause: " + e.getMessage(), e);
            // ??
            failedUnregistered.add(url);
        }
    }

    @Override
    public void unregister(GrpcURL url) {
        super.unregister(url);
        failedRegistered.remove(url);
        failedUnregistered.remove(url);
        try {
            // ?????
            doUnregister(url);
        } catch (Exception e) {
            logger.error("Failed to uregister " + url + ", waiting for retry, cause: " + e.getMessage(), e);
            // ??
            failedUnregistered.add(url);
        }
    }

    @Override
    public void subscribe(GrpcURL url, NotifyListener.NotifyServiceListener listener) {
        super.subscribe(url, listener);
        removeFailedSubscribed(url, listener);
        try {
            // ????
            doSubscribe(url, listener);
        } catch (Exception e) {
            logger.error("Failed to subscribe " + url + ", waiting for retry, cause: " + e.getMessage(), e);
            // ?
            addFailedSubscribed(url, listener);
        }
    }

    @Override
    public void unsubscribe(GrpcURL url, NotifyListener.NotifyServiceListener listener) {
        super.unsubscribe(url, listener);
        removeFailedSubscribed(url, listener);
        try {
            // ?????
            doUnsubscribe(url, listener);
        } catch (Exception e) {
            logger.error("Failed to unsubscribe " + url + ", waiting for retry, cause: " + e.getMessage(), e);
            // ??
            Set<NotifyListener.NotifyServiceListener> listeners = failedUnsubscribed.get(url);
            if (listeners == null) {
                listeners = Sets.newConcurrentHashSet();
                listeners = failedUnsubscribed.putIfAbsent(url, listeners);
            }
            listeners.add(listener);
        }
    }

    @Override
    protected void notify(GrpcURL url, NotifyListener.NotifyServiceListener listener, List<GrpcURL> urls) {
        if (url == null) {
            throw new IllegalArgumentException("notify url == null");
        }
        if (listener == null) {
            throw new IllegalArgumentException("notify listener == null");
        }
        try {
            doNotify(url, listener, urls);
        } catch (Exception t) {
            // ?
            Map<NotifyListener.NotifyServiceListener, List<GrpcURL>> listeners = failedNotified.get(url);
            if (listeners == null) {
                failedNotified.putIfAbsent(url, Maps.newConcurrentMap());
                listeners = failedNotified.get(url);
            }
            listeners.put(listener, urls);
            logger.error("Failed to notify for subscribe " + url + ", waiting for retry, cause: " + t.getMessage(),
                    t);
        }
    }

    protected void doNotify(GrpcURL url, NotifyListener.NotifyServiceListener listener, List<GrpcURL> urls) {
        super.notify(url, listener, urls);
    }

    @Override
    protected void recover() throws Exception {
        // register
        Set<GrpcURL> recoverRegistered = Sets.newHashSet(getRegistered());
        if (!recoverRegistered.isEmpty()) {
            if (logger.isInfoEnabled()) {
                logger.info("Recover register url " + recoverRegistered);
            }
            for (GrpcURL url : recoverRegistered) {
                failedRegistered.add(url);
            }
        }
        // subscribe
        Map<GrpcURL, Set<NotifyListener.NotifyServiceListener>> recoverSubscribed = Maps
                .newHashMap(getSubscribed());
        if (!recoverSubscribed.isEmpty()) {
            if (logger.isInfoEnabled()) {
                logger.info("Recover subscribe url " + recoverSubscribed.keySet());
            }
            for (Map.Entry<GrpcURL, Set<NotifyListener.NotifyServiceListener>> entry : recoverSubscribed
                    .entrySet()) {
                GrpcURL url = entry.getKey();
                for (NotifyListener.NotifyServiceListener listener : entry.getValue()) {
                    addFailedSubscribed(url, listener);
                }
            }
        }
    }

    // ==== ? ====
    protected abstract void doRegister(GrpcURL url);

    protected abstract void doUnregister(GrpcURL url);

    protected abstract void doSubscribe(GrpcURL url, NotifyListener.NotifyServiceListener listener);

    protected abstract void doUnsubscribe(GrpcURL url, NotifyListener.NotifyServiceListener listener);
}