From 3d0b54e67ff4e4b8aafbe7d3ab340a1fb95e3c37 Mon Sep 17 00:00:00 2001 From: Diego Lima Date: Wed, 14 Aug 2013 17:26:31 -0300 Subject: [PATCH] Changes on Disk and Memory cache Using SHA-1 algorithm to avoid key collisions. Using lazy initialization singleton pattern. --- .../dumbledroid/data/cache/DiskCache.java | 115 +++++++++++++----- .../dumbledroid/data/cache/MemoryCache.java | 38 +++--- 2 files changed, 105 insertions(+), 48 deletions(-) diff --git a/Dumbledroid/src/io/leocad/dumbledroid/data/cache/DiskCache.java b/Dumbledroid/src/io/leocad/dumbledroid/data/cache/DiskCache.java index 140bcc4..06031cf 100644 --- a/Dumbledroid/src/io/leocad/dumbledroid/data/cache/DiskCache.java +++ b/Dumbledroid/src/io/leocad/dumbledroid/data/cache/DiskCache.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import android.content.Context; import android.util.Log; @@ -15,18 +17,20 @@ public class DiskCache { private static final String TAG = "DiskCache"; - private static DiskCache INSTANCE; + private static DiskCache sInstance; /** * @param ctx ALWAYS USE getApplicationContext() here. * @return */ - public static DiskCache getInstance(Context ctx) { - - if (INSTANCE == null) { - INSTANCE = new DiskCache(ctx); + public static DiskCache getInstance(Context context) { + if (sInstance == null) { + synchronized (DiskCache.class) { + if (sInstance == null) { + sInstance = new DiskCache(context); + } + } } - - return INSTANCE; + return sInstance; } private final FileController mFileCtrl; @@ -36,45 +40,90 @@ private DiskCache(Context ctx) { } public void cache(String key, AbstractModel model) { + final String fileName = getHashKey(key); + final ModelHolder holder = new ModelHolder(model, System.currentTimeMillis()); - String fileName = String.valueOf(key.hashCode()); - - ModelHolder holder = new ModelHolder(model, System.currentTimeMillis()); + FileOutputStream fos = null; + ObjectOutputStream oos = null; try { - FileOutputStream fos = mFileCtrl.getFileOutputStream(fileName); - ObjectOutputStream oos = new ObjectOutputStream(fos); + fos = mFileCtrl.getFileOutputStream(fileName); + oos = new ObjectOutputStream(fos); oos.writeObject(holder); - - oos.flush(); - oos.close(); - - fos.flush(); - fos.close(); - } catch (IOException e) { - Log.w(TAG, "The file " + fileName + "couldn't be cached. Does this app have permission to ACCESS_EXTERNAL_STORAGE?", e); + Log.w(TAG, "The file " + fileName + " couldn't be cached. Does this app have permission to ACCESS_EXTERNAL_STORAGE ?", e); + } finally { + if(fos != null) { + try { + fos.flush(); + fos.close(); + } catch (IOException e) { + Log.w(TAG, Log.getStackTraceString(e)); + } + } + if(oos != null) { + try { + oos.flush(); + oos.close(); + } catch (IOException e) { + Log.w(TAG, Log.getStackTraceString(e)); + } + } } } public ModelHolder getCached(String key) { + final String fileName = getHashKey(key); - String fileName = String.valueOf(key.hashCode()); - + FileInputStream fis = null; + ObjectInputStream ois = null; try { - FileInputStream fis = mFileCtrl.getFileInputStream(fileName); - ObjectInputStream ois = new ObjectInputStream(fis); - - ModelHolder holder = (ModelHolder) ois.readObject(); + fis = mFileCtrl.getFileInputStream(fileName); + ois = new ObjectInputStream(fis); + final ModelHolder holder = (ModelHolder) ois.readObject(); + return holder; + } catch (IOException e) { + Log.w(TAG, "Can't access file: " + fileName, e); + } catch (ClassNotFoundException e) { + Log.w(TAG, "Can't read object from file: " + fileName, e); + } finally { + if(fis != null) { + try { + fis.close(); + } catch (IOException e) { + Log.w(TAG, Log.getStackTraceString(e)); + } + } + if(ois != null) { + try { + ois.close(); + } catch (IOException e) { + Log.w(TAG, Log.getStackTraceString(e)); + } + } + } + return null; + } - ois.close(); - fis.close(); + private static String getHashKey(String key) { + try { + final MessageDigest mDigest = MessageDigest.getInstance("SHA-1"); + mDigest.update(key.getBytes()); + return bytesToHexString(mDigest.digest()); + } catch (NoSuchAlgorithmException e) {} + return String.valueOf(key.hashCode()); + } - return holder; + private static String bytesToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); - } catch (Exception e) { - Log.w(TAG, "Can't access file: " + fileName, e); - return null; + for (int i = 0; i < bytes.length; i++) { + final String hex = Integer.toHexString(0xFF & bytes[i]); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); } + return sb.toString(); } -} +} \ No newline at end of file diff --git a/Dumbledroid/src/io/leocad/dumbledroid/data/cache/MemoryCache.java b/Dumbledroid/src/io/leocad/dumbledroid/data/cache/MemoryCache.java index 7ae3ec9..f18c9fc 100644 --- a/Dumbledroid/src/io/leocad/dumbledroid/data/cache/MemoryCache.java +++ b/Dumbledroid/src/io/leocad/dumbledroid/data/cache/MemoryCache.java @@ -10,45 +10,53 @@ public class MemoryCache { - private static final MemoryCache INSTANCE = new MemoryCache(); + private static MemoryCache sInstance; + public static MemoryCache getInstance() { - return INSTANCE; + if (sInstance == null) { + synchronized (MemoryCache.class) { + if (sInstance == null) { + sInstance = new MemoryCache(); + } + } + } + return sInstance; } - + private Map> mMap; - + private MemoryCache() { mMap = new HashMap>(); } - + public void cache(String key, AbstractModel model) { - + ModelHolder holder = new ModelHolder(model, System.currentTimeMillis()); - + SoftReference ref = new SoftReference(holder); mMap.put(key, ref); } - + public AbstractModel getCachedOrNull(String key) { SoftReference softReference = mMap.get(key); - + if (softReference == null) { return null; } - + ModelHolder modelHolder = softReference.get(); - + if (modelHolder == null || modelHolder.isExpired()) { //Clear from cache softReference.clear(); mMap.remove(key); - + Log.v("MemoryCache", "Expired from memory! " + key); - + return null; } - + return modelHolder.model; } -} +} \ No newline at end of file