基础框架之LocalCache

import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;


public class LocalCache {
    private static final String TAG = "LocalCache";
    private static final String CACHE_ASE_KEY = "CACHE_ASE_KEY";
    private Map<String, Map<String, Entry>> mCacheMap;

    private String mCacheDirPath;


    private static LocalCache INSTANCE;

    public static void setup(String cacheDirPath) {
        INSTANCE = new LocalCache(cacheDirPath);
    }
    public static LocalCache getInstance() {
        return INSTANCE;
    }

    public LocalCache(String cacheDirPath) {
        mCacheDirPath = cacheDirPath;
        mCacheMap = Collections.synchronizedMap(new HashMap<String, Map<String, Entry>>());
        init();
    }

    private void init() {

        File rootDir = new File(mCacheDirPath);
        String[] list = rootDir.list();
        for (String name : list) {
            String[] split = name.split("_");
            Entry entry = new Entry(split[0], split[1], Integer.parseInt(split[2]));
            Map<String, Entry> map = mCacheMap.get(entry.key);
            if (map == null) {
                map = new HashMap<>();
                mCacheMap.put(entry.key, map);
            }
            map.put(entry.language, entry);
        }
    }


    Observable<String> loadCache(final String key, final String language) {
        return Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext(getCacheData(key, language));
                emitter.onComplete();
            }
        }).onErrorResumeNext(new Function<Throwable, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(@NonNull Throwable throwable) throws Exception {
                return Observable.empty();
            }
        });
    }

    public int getCacheVersion(String key, String language) {
        int version = 0;
        Map<String, Entry> map = mCacheMap.get(key);
        if (map != null) {
            Entry entry = map.get(language);
            if (entry != null) {
                version = entry.version;
            }
        }
        return version;
    }

    public String getCacheData(String key, String language) throws IOException {
        String content = null;
        Map<String, Entry> map = mCacheMap.get(key);
        if (map != null) {
            Entry entry = map.get(language);
            if (entry != null) {
                byte[] data = readCacheData(entry);
                content = decodeData(data);
            }
        }
        return content;
    }

    public void saveCacheData(String key, String language, int version, String content) throws IOException {
        synchronized (key) {
            Map<String, Entry> map = mCacheMap.get(key);
            if (map == null) {
                map = new HashMap<>();
                mCacheMap.put(key, map);
            }
            Entry entry = map.remove(language);
            if (entry != null) {
                deleteCache(entry);
            }
            entry = new Entry(key, language, version);
            byte[] bytes = encodeData(content);
            writeCacheData(entry, bytes);
            map.put(language, entry);
        }
    }

    public void deleteCache(String key, String language) {
        synchronized (key) {
            Map<String, Entry> map = mCacheMap.get(key);
            if (map != null) {
                Entry entry = map.remove(language);
                if (entry != null) {
                    deleteCache(entry);
                }
            }
        }
    }


    private byte[] readCacheData(Entry entry) throws IOException {
        synchronized (entry) {
            File file = new File(mCacheDirPath, String.format("%s_%s_%s", entry.key, entry.language, entry.version));
            Log.d(TAG, "readCacheData size=" + file.length() + "  path=>" + file.getAbsolutePath());
            if (file.exists()) {
                FileInputStream ips = new FileInputStream(file);
                ByteArrayOutputStream ops = new ByteArrayOutputStream();
                byte[] buff = new byte[4096]; int len;
                while ((len = ips.read(buff)) != -1) {
                    ops.write(buff, 0, len);
                }
                ips.close();
                return ops.toByteArray();
            }
            return null;
        }
    }

    private void writeCacheData(Entry entry, byte[] data) throws IOException {
        synchronized (entry) {
            File file = new File(mCacheDirPath, String.format("%s_%s_%s", entry.key, entry.language, entry.version));
            FileOutputStream ops = new FileOutputStream(file);
            ops.write(data);
            ops.flush();
            ops.close();
            Log.d(TAG, "writeCacheData size=" + file.length() + "  path=>" + file.getAbsolutePath());
        }
    }


    private void deleteCache(Entry entry) {
        synchronized (entry) {
            File file = new File(mCacheDirPath, String.format("%s_%s_%s", entry.key, entry.language, entry.version));
            file.delete();
        }
    }



    private String decodeData(byte[] data) {
        try {
            Log.d(TAG, "decodeData=>" + new String(data, "UTF-8"));
            byte[] rawKey = MessageDigest.getInstance("MD5").digest(CACHE_ASE_KEY.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] bytes = Base64.decode(data, Base64.NO_WRAP);
            return new String(cipher.doFinal(bytes), "UTF-8");
        } catch (Exception e) {
            Log.e(TAG, "decodeAES", e);
        }
        return null;
    }

    private byte[] encodeData(String content) {
        try {
            byte[] rawKey = MessageDigest.getInstance("MD5").digest(CACHE_ASE_KEY.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] bytes = cipher.doFinal(content.getBytes("UTF-8"));
            byte[] encode = Base64.encode(bytes, Base64.NO_WRAP);
            Log.d(TAG, "encodeData=>" + new String(encode, "UTF-8"));
            return encode;
        } catch (Exception e) {
            Log.e(TAG, "encodeAES", e);
        }
        return null;
    }



    private final class Entry {
        private final String key;
        private final String language;
        private int version;

        public Entry(String key, String language, int version) {
            this.key = key;
            this.language = language;
            this.version = version;
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值