|
@@ -21,22 +21,46 @@ import okio.BufferedSink;
|
|
import okio.Okio;
|
|
import okio.Okio;
|
|
import rx.Observable;
|
|
import rx.Observable;
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Class used to create chapter cache
|
|
|
|
+ * For each image in a chapter a file is created
|
|
|
|
+ * For each chapter a Json list is created and converted to a file.
|
|
|
|
+ * The files are in format *md5key*.0
|
|
|
|
+ */
|
|
public class ChapterCache {
|
|
public class ChapterCache {
|
|
|
|
|
|
|
|
+ /** Name of cache directory. */
|
|
private static final String PARAMETER_CACHE_DIRECTORY = "chapter_disk_cache";
|
|
private static final String PARAMETER_CACHE_DIRECTORY = "chapter_disk_cache";
|
|
|
|
+
|
|
|
|
+ /** Application cache version. */
|
|
private static final int PARAMETER_APP_VERSION = 1;
|
|
private static final int PARAMETER_APP_VERSION = 1;
|
|
|
|
+
|
|
|
|
+ /** The number of values per cache entry. Must be positive. */
|
|
private static final int PARAMETER_VALUE_COUNT = 1;
|
|
private static final int PARAMETER_VALUE_COUNT = 1;
|
|
|
|
+
|
|
|
|
+ /** The maximum number of bytes this cache should use to store. */
|
|
private static final int PARAMETER_CACHE_SIZE = 75 * 1024 * 1024;
|
|
private static final int PARAMETER_CACHE_SIZE = 75 * 1024 * 1024;
|
|
|
|
|
|
- private Context context;
|
|
|
|
- private Gson gson;
|
|
|
|
|
|
+ /** Interface to global information about an application environment. */
|
|
|
|
+ private final Context context;
|
|
|
|
+
|
|
|
|
+ /** Google Json class used for parsing json files. */
|
|
|
|
+ private final Gson gson;
|
|
|
|
|
|
|
|
+ /** Cache class used for cache management. */
|
|
private DiskLruCache diskCache;
|
|
private DiskLruCache diskCache;
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Constructor of ChapterCache.
|
|
|
|
+ * @param context application environment interface.
|
|
|
|
+ */
|
|
public ChapterCache(Context context) {
|
|
public ChapterCache(Context context) {
|
|
this.context = context;
|
|
this.context = context;
|
|
|
|
+
|
|
|
|
+ // Initialize Json handler.
|
|
gson = new Gson();
|
|
gson = new Gson();
|
|
|
|
|
|
|
|
+ // Try to open cache in default cache directory.
|
|
try {
|
|
try {
|
|
diskCache = DiskLruCache.open(
|
|
diskCache = DiskLruCache.open(
|
|
new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY),
|
|
new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY),
|
|
@@ -45,43 +69,67 @@ public class ChapterCache {
|
|
PARAMETER_CACHE_SIZE
|
|
PARAMETER_CACHE_SIZE
|
|
);
|
|
);
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
- // Do Nothing.
|
|
|
|
|
|
+ // Do Nothing. TODO error handling.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public boolean remove(String file) {
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Remove file from cache.
|
|
|
|
+ * @param file name of chapter file md5.0.
|
|
|
|
+ * @return false if file is journal or error else returns status of deletion.
|
|
|
|
+ */
|
|
|
|
+ public boolean removeFileFromCache(String file) {
|
|
|
|
+ // Make sure we don't delete the journal file (keeps track of cache).
|
|
if (file.equals("journal") || file.startsWith("journal."))
|
|
if (file.equals("journal") || file.startsWith("journal."))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
try {
|
|
try {
|
|
|
|
+ // Take dot(.) substring to get filename without the .0 at the end.
|
|
String key = file.substring(0, file.lastIndexOf("."));
|
|
String key = file.substring(0, file.lastIndexOf("."));
|
|
|
|
+ // Remove file from cache.
|
|
return diskCache.remove(key);
|
|
return diskCache.remove(key);
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Returns directory of cache.
|
|
|
|
+ * @return directory of cache.
|
|
|
|
+ */
|
|
public File getCacheDir() {
|
|
public File getCacheDir() {
|
|
return diskCache.getDirectory();
|
|
return diskCache.getDirectory();
|
|
}
|
|
}
|
|
|
|
|
|
- public long getRealSize() {
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Returns real size of directory.
|
|
|
|
+ * @return real size of directory.
|
|
|
|
+ */
|
|
|
|
+ private long getRealSize() {
|
|
return DiskUtils.getDirectorySize(getCacheDir());
|
|
return DiskUtils.getDirectorySize(getCacheDir());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Returns real size of directory in human readable format.
|
|
|
|
+ * @return real size of directory.
|
|
|
|
+ */
|
|
public String getReadableSize() {
|
|
public String getReadableSize() {
|
|
return Formatter.formatFileSize(context, getRealSize());
|
|
return Formatter.formatFileSize(context, getRealSize());
|
|
}
|
|
}
|
|
|
|
|
|
- public void setSize(int value) {
|
|
|
|
- diskCache.setMaxSize(value * 1024 * 1024);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Get page objects from cache.
|
|
|
|
+ * @param chapterUrl the url of the chapter.
|
|
|
|
+ * @return list of chapter pages.
|
|
|
|
+ */
|
|
public Observable<List<Page>> getPageUrlsFromDiskCache(final String chapterUrl) {
|
|
public Observable<List<Page>> getPageUrlsFromDiskCache(final String chapterUrl) {
|
|
return Observable.create(subscriber -> {
|
|
return Observable.create(subscriber -> {
|
|
try {
|
|
try {
|
|
|
|
+ // Get list of pages from chapterUrl.
|
|
List<Page> pages = getPageUrlsFromDiskCacheImpl(chapterUrl);
|
|
List<Page> pages = getPageUrlsFromDiskCacheImpl(chapterUrl);
|
|
|
|
+ // Provides the Observer with a new item to observe.
|
|
subscriber.onNext(pages);
|
|
subscriber.onNext(pages);
|
|
|
|
+ // Notify the Observer that finished sending push-based notifications.
|
|
subscriber.onCompleted();
|
|
subscriber.onCompleted();
|
|
} catch (Throwable e) {
|
|
} catch (Throwable e) {
|
|
subscriber.onError(e);
|
|
subscriber.onError(e);
|
|
@@ -89,18 +137,31 @@ public class ChapterCache {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- private List<Page> getPageUrlsFromDiskCacheImpl(String chapterUrl) throws IOException {
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Implementation of the getPageUrlsFromDiskCache() function
|
|
|
|
+ * @param chapterUrl the url of the chapter
|
|
|
|
+ * @return returns list of chapter pages
|
|
|
|
+ * @throws IOException does nothing atm
|
|
|
|
+ */
|
|
|
|
+ private List<Page> getPageUrlsFromDiskCacheImpl(String chapterUrl) throws IOException /*TODO IOException never thrown*/ {
|
|
|
|
+ // Initialize snapshot (a snapshot of the values for an entry).
|
|
DiskLruCache.Snapshot snapshot = null;
|
|
DiskLruCache.Snapshot snapshot = null;
|
|
|
|
+
|
|
|
|
+ // Initialize list of pages.
|
|
List<Page> pages = null;
|
|
List<Page> pages = null;
|
|
|
|
|
|
try {
|
|
try {
|
|
|
|
+ // Create md5 key and retrieve snapshot.
|
|
String key = DiskUtils.hashKeyForDisk(chapterUrl);
|
|
String key = DiskUtils.hashKeyForDisk(chapterUrl);
|
|
snapshot = diskCache.get(key);
|
|
snapshot = diskCache.get(key);
|
|
|
|
|
|
|
|
+
|
|
|
|
+ // Convert JSON string to list of objects.
|
|
Type collectionType = new TypeToken<List<Page>>() {}.getType();
|
|
Type collectionType = new TypeToken<List<Page>>() {}.getType();
|
|
pages = gson.fromJson(snapshot.getString(0), collectionType);
|
|
pages = gson.fromJson(snapshot.getString(0), collectionType);
|
|
|
|
+
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
- // Do Nothing.
|
|
|
|
|
|
+ // Do Nothing. //TODO error handling?
|
|
} finally {
|
|
} finally {
|
|
if (snapshot != null) {
|
|
if (snapshot != null) {
|
|
snapshot.close();
|
|
snapshot.close();
|
|
@@ -109,18 +170,30 @@ public class ChapterCache {
|
|
return pages;
|
|
return pages;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Add page urls to disk cache.
|
|
|
|
+ * @param chapterUrl the url of the chapter.
|
|
|
|
+ * @param pages list of chapter pages.
|
|
|
|
+ */
|
|
public void putPageUrlsToDiskCache(final String chapterUrl, final List<Page> pages) {
|
|
public void putPageUrlsToDiskCache(final String chapterUrl, final List<Page> pages) {
|
|
|
|
+ // Convert list of pages to json string.
|
|
String cachedValue = gson.toJson(pages);
|
|
String cachedValue = gson.toJson(pages);
|
|
|
|
|
|
|
|
+ // Initialize the editor (edits the values for an entry).
|
|
DiskLruCache.Editor editor = null;
|
|
DiskLruCache.Editor editor = null;
|
|
|
|
+
|
|
|
|
+ // Initialize OutputStream.
|
|
OutputStream outputStream = null;
|
|
OutputStream outputStream = null;
|
|
|
|
+
|
|
try {
|
|
try {
|
|
|
|
+ // Get editor from md5 key.
|
|
String key = DiskUtils.hashKeyForDisk(chapterUrl);
|
|
String key = DiskUtils.hashKeyForDisk(chapterUrl);
|
|
editor = diskCache.edit(key);
|
|
editor = diskCache.edit(key);
|
|
if (editor == null) {
|
|
if (editor == null) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Write chapter urls to cache.
|
|
outputStream = new BufferedOutputStream(editor.newOutputStream(0));
|
|
outputStream = new BufferedOutputStream(editor.newOutputStream(0));
|
|
outputStream.write(cachedValue.getBytes());
|
|
outputStream.write(cachedValue.getBytes());
|
|
outputStream.flush();
|
|
outputStream.flush();
|
|
@@ -128,7 +201,7 @@ public class ChapterCache {
|
|
diskCache.flush();
|
|
diskCache.flush();
|
|
editor.commit();
|
|
editor.commit();
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
- // Do Nothing.
|
|
|
|
|
|
+ // Do Nothing. TODO error handling?
|
|
} finally {
|
|
} finally {
|
|
if (editor != null) {
|
|
if (editor != null) {
|
|
editor.abortUnlessCommitted();
|
|
editor.abortUnlessCommitted();
|
|
@@ -137,12 +210,17 @@ public class ChapterCache {
|
|
try {
|
|
try {
|
|
outputStream.close();
|
|
outputStream.close();
|
|
} catch (IOException ignore) {
|
|
} catch (IOException ignore) {
|
|
- // Do Nothing.
|
|
|
|
|
|
+ // Do Nothing. TODO error handling?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Check if image is in cache.
|
|
|
|
+ * @param imageUrl url of image.
|
|
|
|
+ * @return true if in cache otherwise false.
|
|
|
|
+ */
|
|
public boolean isImageInCache(final String imageUrl) {
|
|
public boolean isImageInCache(final String imageUrl) {
|
|
try {
|
|
try {
|
|
return diskCache.get(DiskUtils.hashKeyForDisk(imageUrl)) != null;
|
|
return diskCache.get(DiskUtils.hashKeyForDisk(imageUrl)) != null;
|
|
@@ -152,8 +230,14 @@ public class ChapterCache {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Get image path from url.
|
|
|
|
+ * @param imageUrl url of image.
|
|
|
|
+ * @return path of image.
|
|
|
|
+ */
|
|
public String getImagePath(final String imageUrl) {
|
|
public String getImagePath(final String imageUrl) {
|
|
try {
|
|
try {
|
|
|
|
+ // Get file from md5 key.
|
|
String imageName = DiskUtils.hashKeyForDisk(imageUrl) + ".0";
|
|
String imageName = DiskUtils.hashKeyForDisk(imageUrl) + ".0";
|
|
File file = new File(diskCache.getDirectory(), imageName);
|
|
File file = new File(diskCache.getDirectory(), imageName);
|
|
return file.getCanonicalPath();
|
|
return file.getCanonicalPath();
|
|
@@ -163,17 +247,28 @@ public class ChapterCache {
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Add image to cache
|
|
|
|
+ * @param imageUrl url of image.
|
|
|
|
+ * @param response http response from page.
|
|
|
|
+ * @throws IOException image error.
|
|
|
|
+ */
|
|
public void putImageToDiskCache(final String imageUrl, final Response response) throws IOException {
|
|
public void putImageToDiskCache(final String imageUrl, final Response response) throws IOException {
|
|
|
|
+ // Initialize editor (edits the values for an entry).
|
|
DiskLruCache.Editor editor = null;
|
|
DiskLruCache.Editor editor = null;
|
|
|
|
+
|
|
|
|
+ // Initialize BufferedSink (used for small writes).
|
|
BufferedSink sink = null;
|
|
BufferedSink sink = null;
|
|
|
|
|
|
try {
|
|
try {
|
|
|
|
+ // Get editor from md5 key.
|
|
String key = DiskUtils.hashKeyForDisk(imageUrl);
|
|
String key = DiskUtils.hashKeyForDisk(imageUrl);
|
|
editor = diskCache.edit(key);
|
|
editor = diskCache.edit(key);
|
|
if (editor == null) {
|
|
if (editor == null) {
|
|
throw new IOException("Unable to edit key");
|
|
throw new IOException("Unable to edit key");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Initialize OutputStream and write image.
|
|
OutputStream outputStream = new BufferedOutputStream(editor.newOutputStream(0));
|
|
OutputStream outputStream = new BufferedOutputStream(editor.newOutputStream(0));
|
|
sink = Okio.buffer(Okio.sink(outputStream));
|
|
sink = Okio.buffer(Okio.sink(outputStream));
|
|
sink.writeAll(response.body().source());
|
|
sink.writeAll(response.body().source());
|