package com.qihoo.finance.chronus.common.ehcache;

import org.springframework.cache.Cache;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.Map;

/**
 * 本地缓存加载器
 * 作用：应用启动后，初始化内存；结合Spring task，定时刷新缓存;AB切换机制，刷新不影响缓存使用。
 * 避免缓存被击穿
 * Created by zhaoliping on 2016/6/8.
 */
public abstract class AbstractLocalCacheLoader implements ApplicationListener<ContextRefreshedEvent> {

    protected String switchA = "";
    protected String switchB = "";
    protected String current = "";
    protected ChronusEhcache chronusEhcache;

    public AbstractLocalCacheLoader(ChronusEhcache chronusEhcache) {
        this.chronusEhcache = chronusEhcache;
        switchA = getCacheName() + "_A";
        switchB = getCacheName() + "_B";
        current = switchA;

    }

    /**
     * 自定义缓存定制，初始化数据
     *
     * @return 缓存字典
     */
    public abstract Map<String, Object> init();

    /**
     * 自定义缓存定制，指定缓存名字
     *
     * @return
     */
    protected abstract String getCacheName();


    /**
     * 缓存刷新
     */
    public synchronized void update() {
        //缓存AB切换
        change();

        //加载数据
        Map<String, Object> datas = init();
        if (datas != null && !datas.isEmpty()) {
            for (Map.Entry<String, Object> item : datas.entrySet()) {
                put(item.getKey(), item.getValue());
            }
        }

        //缓存切换
        current = switchA;
        //老缓存清理
        Cache cache = chronusEhcache.getCache(switchB);
        if (cache != null) {
            cache.clear();
        }
    }

    /**
     * 增加缓存值
     *
     * @param key
     * @param value
     */
    protected void put(String key, Object value) {
        chronusEhcache.put(switchA, key, value);
    }

    /**
     * 取缓存值
     *
     * @param key
     * @return
     */
    public <T> T get(String key) {
        return (T) chronusEhcache.get(current, key);
    }

    /**
     * AB切换
     */
    private void change() {
        String temp = switchA;
        switchA = switchB;
        switchB = temp;
    }

    /**
     * 在spring容器加载完成后，执行cache初始化
     *
     * @param contextRefreshedEvent
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        update();
    }
}
