1/*
2 * Copyright (c) 2013. Bump Technologies Inc. All Rights Reserved.
3 */
4
5package com.bumptech.glide.load.engine.cache;
6
7import android.util.Log;
8
9import com.bumptech.glide.disklrucache.DiskLruCache;
10import com.bumptech.glide.load.Key;
11
12import java.io.File;
13import java.io.IOException;
14
15/**
16 * The default DiskCache implementation. There must be no more than one active instance for a given
17 * directory at a time.
18 *
19 * @see #get(java.io.File, int)
20 */
21public class DiskLruCacheWrapper implements DiskCache {
22    private static final String TAG = "DiskLruCacheWrapper";
23
24    private static final int APP_VERSION = 1;
25    private static final int VALUE_COUNT = 1;
26    private static DiskLruCacheWrapper wrapper = null;
27
28    private final SafeKeyGenerator safeKeyGenerator;
29    private final File directory;
30    private final int maxSize;
31    private DiskLruCache diskLruCache;
32
33    /**
34     * Get a DiskCache in the given directory and size. If a disk cache has alread been created with
35     * a different directory and/or size, it will be returned instead and the new arguments
36     * will be ignored.
37     *
38     * @param directory The directory for the disk cache
39     * @param maxSize The max size for the disk cache
40     * @return The new disk cache with the given arguments, or the current cache if one already exists
41     */
42    public static synchronized DiskCache get(File directory, int maxSize) {
43        // TODO calling twice with different arguments makes it return the cache for the same directory, it's public!
44        if (wrapper == null) {
45            wrapper = new DiskLruCacheWrapper(directory, maxSize);
46        }
47        return wrapper;
48    }
49
50    protected DiskLruCacheWrapper(File directory, int maxSize) {
51        this.directory = directory;
52        this.maxSize = maxSize;
53        this.safeKeyGenerator = new SafeKeyGenerator();
54    }
55
56    private synchronized DiskLruCache getDiskCache() throws IOException {
57        if (diskLruCache == null) {
58            diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
59        }
60        return diskLruCache;
61    }
62
63    @Override
64    public File get(Key key) {
65        String safeKey = safeKeyGenerator.getSafeKey(key);
66        File result = null;
67        try {
68            //It is possible that the there will be a put in between these two gets. If so that shouldn't be a problem
69            //because we will always put the same value at the same key so our input streams will still represent
70            //the same data
71            final DiskLruCache.Value value = getDiskCache().get(safeKey);
72            if (value != null) {
73                result = value.getFile(0);
74            }
75        } catch (IOException e) {
76            if (Log.isLoggable(TAG, Log.WARN)) {
77                Log.w(TAG, "Unable to get from disk cache", e);
78            }
79        }
80        return result;
81    }
82
83    @Override
84    public void put(Key key, Writer writer) {
85        String safeKey = safeKeyGenerator.getSafeKey(key);
86        try {
87            DiskLruCache.Editor editor = getDiskCache().edit(safeKey);
88            // Editor will be null if there are two concurrent puts. In the worst case we will just silently fail.
89            if (editor != null) {
90                try {
91                    File file = editor.getFile(0);
92                    if (writer.write(file)) {
93                        editor.commit();
94                    }
95                } finally {
96                    editor.abortUnlessCommitted();
97                }
98            }
99        } catch (IOException e) {
100            if (Log.isLoggable(TAG, Log.WARN)) {
101                Log.w(TAG, "Unable to put to disk cache", e);
102            }
103        }
104    }
105
106    @Override
107    public void delete(Key key) {
108        String safeKey = safeKeyGenerator.getSafeKey(key);
109        try {
110            getDiskCache().remove(safeKey);
111        } catch (IOException e) {
112            if (Log.isLoggable(TAG, Log.WARN)) {
113                Log.w(TAG, "Unable to delete from disk cache", e);
114            }
115        }
116    }
117}
118