/* * Copyright (c) 2015 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com> * All Rights Reserved. */ package me.zhanghai.android.douya.util; import android.util.LruCache; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; import com.jakewharton.disklrucache.DiskLruCache; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.lang.reflect.Type; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class DiskCache { private DiskLruCache mCache; private SafeKeyGenerator mSafeKeyGenerator = new SafeKeyGenerator(); private DiskCache(DiskLruCache cache) { mCache = cache; } public static DiskCache openOrThrow(File directory, int version, long maxSize) throws IOException { return new DiskCache(DiskLruCache.open(directory, version, 1, maxSize)); } public static DiskCache open(File directory, int version, long maxSize) { try { return openOrThrow(directory, version, maxSize); } catch (IOException e) { e.printStackTrace(); return null; } } private DiskLruCache.Snapshot getOrThrow(String key) throws IOException, NullPointerException { DiskLruCache.Snapshot snapshot = mCache.get(mSafeKeyGenerator.getSafeKey(key)); if (snapshot == null) { throw new NullPointerException("DiskLruCache.get() returned null"); } return snapshot; } public InputStream getInputStreamOrThrow(String key) throws IOException, NullPointerException { return getOrThrow(key).getInputStream(0); } public InputStream getInputStream(String key) { try { return getInputStreamOrThrow(key); } catch (IOException | NullPointerException e) { e.printStackTrace(); return null; } } public String getStringOrThrow(String key) throws IOException { return getOrThrow(key).getString(0); } public String getString(String key) { try { return getStringOrThrow(key); } catch (IOException | NullPointerException e) { e.printStackTrace(); return null; } } public <T> T getGsonOrThrow(String key, Type type) throws IOException, JsonParseException { // Gson.fromJson() creates a JsonReader which does its own buffering. Reader reader = new InputStreamReader(getInputStreamOrThrow(key)); try { return GsonHelper.get().fromJson(reader, type); } finally { reader.close(); } } public <T> T getGson(String key, Type type) { try { return getGsonOrThrow(key, type); } catch (IOException | NullPointerException e) { e.printStackTrace(); return null; } } public <T> T getGson(String key, TypeToken<T> typeToken) { return getGson(key, typeToken.getType()); } private DiskLruCache.Editor editOrThrow(String key) throws IOException, NullPointerException { DiskLruCache.Editor editor = mCache.edit(mSafeKeyGenerator.getSafeKey(key)); if (editor == null) { throw new NullPointerException("DiskLruCache.edit() returned null"); } return editor; } public void putBytesOrThrow(String key, byte[] value) throws IOException, NullPointerException { DiskLruCache.Editor editor = editOrThrow(key); try { editor.newOutputStream(0).write(value); editor.commit(); } finally { editor.abortUnlessCommitted(); } } public void putBytes(String key, byte[] value) { try { putBytesOrThrow(key, value); } catch (IOException | NullPointerException e) { e.printStackTrace(); } } public void putStringOrThrow(String key, String value) throws IOException, NullPointerException { putBytesOrThrow(key, value.getBytes(StandardCharsetsCompat.UTF_8)); } public void putString(String key, String value) { try { putStringOrThrow(key, value); } catch (IOException | NullPointerException e) { e.printStackTrace(); } } public <T> void putGsonOrThrow(String key, T value, Type type) throws IOException, NullPointerException { DiskLruCache.Editor editor = editOrThrow(key); try { Writer writer = new BufferedWriter(new OutputStreamWriter(editor.newOutputStream(0))); try { GsonHelper.get().toJson(value, type, writer); } finally { writer.close(); } editor.commit(); } finally { editor.abortUnlessCommitted(); } } public <T> void putGson(String key, T value, Type type) { try { putGsonOrThrow(key, value, type); } catch (IOException | NullPointerException e) { e.printStackTrace(); } } public <T> void putGson(String key, T value, TypeToken<T> typeToken) { putGson(key, value, typeToken.getType()); } public boolean removeOrThrow(String key) throws IOException { return mCache.remove(key); } public boolean remove(String key) { try { return removeOrThrow(key); } catch (IOException e) { e.printStackTrace(); return false; } } public void deleteOrThrow() throws IOException { mCache.delete(); mCache = null; } public void delete() { try { deleteOrThrow(); } catch (IOException e) { e.printStackTrace(); } } public void closeOrThrow() throws IOException { mCache.close(); } public void close() { try { closeOrThrow(); } catch (IOException e) { e.printStackTrace(); } } private static class SafeKeyGenerator { private final LruCache<String, String> loadIdToSafeHash = new LruCache<>(100); public String getSafeKey(String key) { String safeKey; synchronized (loadIdToSafeHash) { safeKey = loadIdToSafeHash.get(key); } if (safeKey == null) { try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(key.getBytes(StandardCharsetsCompat.UTF_8)); safeKey = IoUtils.byteArrayToHexString(messageDigest.digest(), true); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } synchronized (loadIdToSafeHash) { loadIdToSafeHash.put(key, safeKey); } } return safeKey; } } }