All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.n3r.diamond.client.impl.DiamondSubscriber Maven / Gradle / Ivy

package org.n3r.diamond.client.impl;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.apache.commons.lang3.StringUtils;
import org.n3r.diamond.client.DiamondAxis;
import org.n3r.diamond.client.DiamondListener;
import org.n3r.diamond.client.cache.DiamondCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class DiamondSubscriber implements Closeable {
    private static DiamondSubscriber instance = new DiamondSubscriber();

    public static DiamondSubscriber getInstance() {
        return instance;
    }

    private Logger log = LoggerFactory.getLogger(DiamondSubscriber.class);

    private final LoadingCache metaCache
            = CacheBuilder.newBuilder()
            .build(new CacheLoader() {
                @Override
                public DiamondMeta load(DiamondAxis key) throws Exception {
                    start();
                    return new DiamondMeta(key);
                }
            });

    private volatile DiamondManagerConf managerConfig = new DiamondManagerConf();

    private ScheduledExecutorService scheduler;
    private LocalDiamondMiner localDiamondMiner = new LocalDiamondMiner();
    private ServerAddressesMiner serverAddressesMiner;
    private SnapshotMiner snapshotMiner;
    private DiamondCache diamondCache;

    private volatile boolean running;

    private DiamondRemoteChecker diamondRemoteChecker;

    private DiamondSubscriber() {
    }

    public void addDiamondListener(DiamondAxis diamondAxis, DiamondListener diamondListener) {
        diamondRemoteChecker.addDiamondListener(diamondAxis, diamondListener);
    }

    public void removeDiamondListener(DiamondAxis diamondAxis, DiamondListener diamondListener) {
        diamondRemoteChecker.removeDiamondListener(diamondAxis, diamondListener);
    }

    public synchronized void start() {
        if (running) return;

        if (null == scheduler || scheduler.isTerminated())
            scheduler = Executors.newSingleThreadScheduledExecutor();

        localDiamondMiner.start(managerConfig);

        snapshotMiner = new SnapshotMiner(managerConfig);
        diamondCache = new DiamondCache(snapshotMiner);

        if (!ClientProperties.isPureLocalMode() || MockDiamondServer.isTestMode()) {
            DiamondHttpClient diamondHttpClient = new DiamondHttpClient(managerConfig);

            serverAddressesMiner = new ServerAddressesMiner(
                    managerConfig, scheduler, diamondHttpClient);
            serverAddressesMiner.start();

            diamondRemoteChecker = new DiamondRemoteChecker(this,
                    managerConfig, diamondCache, diamondHttpClient);

            log.info("diamond servers {}", managerConfig.getDiamondServers());

            rotateCheckDiamonds();
        }

        running = true;

        addShutdownHook();
    }


    private void addShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                close();
            }
        });
    }

    private void rotateCheckDiamonds() {
        int pollingInterval = managerConfig.getPollingInterval();
        scheduler.schedule(new Runnable() {
            @Override
            public void run() {
                new DiamondExtenderManager().loadDiamondExtenders();
            }
        }, 5, TimeUnit.SECONDS);

        scheduler.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                rotateCheckDiamondsTask();
            }

        }, pollingInterval, pollingInterval, TimeUnit.SECONDS);
    }

    private void rotateCheckDiamondsTask() {
        try {
            checkLocal();
            diamondRemoteChecker.checkRemote();
            checkSnapshot();
        } catch (Exception e) {
            log.warn("rotateCheckDiamondsTask error {}", e.getMessage());
        }
    }


    @Override
    public synchronized void close() {
        if (!running) return;
        running = false;

        log.warn("start to close DiamondSubscriber");

        localDiamondMiner.stop();
        serverAddressesMiner.stop();

        scheduler.shutdownNow();

//        metaCache.invalidateAll();
        diamondRemoteChecker.shutdown();
        diamondCache.close();

        log.warn("end to close DiamondSubscriber");
    }

    public DiamondRemoteChecker getDiamondRemoteChecker() {
        return diamondRemoteChecker;
    }

    public String retrieveDiamondLocalAndRemote(DiamondAxis diamondAxis, long timeout) {
        DiamondMeta diamondMeta = getCachedMeta(diamondAxis);
        // local first
        try {
            String localConfig = localDiamondMiner.readLocal(diamondMeta);
            if (localConfig != null) {
                diamondMeta.incSuccCounterAndGet();
                saveSnapshot(diamondAxis, localConfig);
                return localConfig;
            }
        } catch (Exception e) {
            log.error("get local error", e);
        }

        String result = diamondRemoteChecker.retrieveRemote(diamondAxis, timeout, true);
        if (result != null) {
            saveSnapshot(diamondAxis, result);
            diamondMeta.incSuccCounterAndGet();
        }

        return result;
    }

    public void saveSnapshot(DiamondAxis diamondAxis, String diamondContent) {
        snapshotMiner.saveSnaptshot(diamondAxis, diamondContent);
    }

    public String getDiamond(DiamondAxis diamondAxis, long timeout) {
        if (MockDiamondServer.isTestMode())
            return MockDiamondServer.getDiamond(diamondAxis);

        try {
            String result = retrieveDiamondLocalAndRemote(diamondAxis, timeout);
            if (StringUtils.isNotBlank(result)) return result;
        } catch (Exception t) {
            log.error(t.getMessage());
        }

        if (MockDiamondServer.isTestMode()) return null;

        return getSnapshot(diamondAxis);
    }


    public String getSnapshot(DiamondAxis diamondAxis) {
        try {
            DiamondMeta diamondMeta = getCachedMeta(diamondAxis);
            String diamondContent = snapshotMiner.getSnapshot(diamondAxis);
            if (diamondContent != null && diamondMeta != null)
                diamondMeta.incSuccCounterAndGet();

            return diamondContent;
        } catch (Exception e) {
            log.error("getSnapshot diamondAxis {} error {}", diamondAxis, e.getMessage());
            return null;
        }
    }

    public void removeSnapshot(DiamondAxis diamondAxis) {
        snapshotMiner.removeSnapshot(diamondAxis);
    }

    public void checkSnapshot() {
        for (Map.Entry entry : metaCache.asMap().entrySet()) {
            final DiamondMeta diamondMeta = entry.getValue();

            if (diamondMeta.isUseLocal()) continue;
            if (diamondMeta.getFetchCount() > 0) continue;

            String diamond = getSnapshot(diamondMeta.getDiamondAxis());
            if (diamond != null)
                diamondRemoteChecker.onDiamondChanged(diamondMeta, diamond);
        }
    }

    public DiamondMeta getCachedMeta(DiamondAxis diamondAxis) {
        return metaCache.getUnchecked(diamondAxis);
    }

    public void checkLocal() {
        for (Map.Entry entry : metaCache.asMap().entrySet()) {
            final DiamondMeta diamondMeta = entry.getValue();

            try {
                String content = localDiamondMiner.checkLocal(diamondMeta);
                if (null != content) {
                    log.info("local config read, {}", diamondMeta.getDiamondAxis());

                    diamondRemoteChecker.onDiamondChanged(diamondMeta, content);
                }
            } catch (Exception e) {
                log.error("check local error", e);
            }
        }
    }


    public String createProbeUpdateString() {
        StringBuilder probeModifyBuilder = new StringBuilder();
        for (Map.Entry entry : metaCache.asMap().entrySet()) {
            final DiamondMeta data = entry.getValue();
            if (data.isUseLocal()) continue;

            DiamondAxis axis = data.getDiamondAxis();

            probeModifyBuilder.append(axis.getDataId())
                    .append(Constants.WORD_SEPARATOR).append(axis.getGroup())
                    .append(Constants.WORD_SEPARATOR).append(data.getMd5())
                    .append(Constants.LINE_SEPARATOR);
        }

        return probeModifyBuilder.toString();
    }

    public Object getCache(DiamondAxis diamondAxis, int timeoutMillis, Object... dynamics) {
        String diamondContent = getDiamond(diamondAxis, timeoutMillis);
        if (diamondContent == null) return null;

        return diamondCache.getCache(diamondAxis, diamondContent, dynamics);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy