package es.usc.citius.servando.calendula.util; import android.util.Log; import com.j256.ormlite.dao.CloseableIterator; import com.j256.ormlite.dao.Dao; import org.joda.time.DateTime; import org.joda.time.Duration; import java.sql.SQLException; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import es.usc.citius.servando.calendula.database.DB; import es.usc.citius.servando.calendula.database.HtmlCacheDAO; import es.usc.citius.servando.calendula.persistence.HtmlCacheEntry; /** * Created by alvaro.brey on 31/10/16. */ public class HtmlCacheManager { public static final Long DEFAULT_TTL_MILLIS = Duration.standardMinutes(5).getMillis(); //5 minutes private static HtmlCacheManager theInstance = null; private Dao<HtmlCacheEntry, Long> dao = null; private final static String TAG = "HtmlCacheManager"; private HtmlCacheManager() { } public static HtmlCacheManager getInstance() { //lazy initialization if (theInstance == null) theInstance = new HtmlCacheManager(); return theInstance; } private HtmlCacheEntry retrieve(final int hashCode) { final Dao<HtmlCacheEntry, Long> dao = getDao(); try { List<HtmlCacheEntry> htmlCacheEntries = dao.queryForEq(HtmlCacheEntry.COLUMN_HASHCODE, hashCode); if (htmlCacheEntries.isEmpty()) { return null; } else if (htmlCacheEntries.size() > 1) { Log.w(TAG, "Inconsistent state of cache: hashcode" + hashCode + " is not unique. Deleting all copies."); for (HtmlCacheEntry entry : htmlCacheEntries) { remove(entry); } return null; } else { if (checkTtl(htmlCacheEntries.get(0))) { return htmlCacheEntries.get(0); } else { Log.d(TAG, "retrieve: Deleting invalid entry with hashCode: " + hashCode); remove(htmlCacheEntries.get(0)); return null; } } } catch (SQLException e) { Log.e(TAG, "retrieve: ", e); return null; } } private boolean checkTtl(HtmlCacheEntry entry) { final Date timestamp = entry.getTimestamp(); long diff = DateTime.now().getMillis() - timestamp.getTime(); return diff < entry.getTtl(); } public boolean isCached(final String url) { final int hashCode = url.hashCode(); HtmlCacheEntry entry = retrieve(hashCode); return entry != null; } public String get(final String url) { final int hashCode = url.hashCode(); HtmlCacheEntry entry = retrieve(hashCode); if (entry != null) return entry.getData(); return null; } public boolean put(final String url, final String data, final Duration ttlDuration) { final Long ttl = ttlDuration == null ? DEFAULT_TTL_MILLIS : ttlDuration.getMillis(); final int hashCode = url.hashCode(); HtmlCacheEntry entry = retrieve(hashCode); if (entry != null) remove(entry); HtmlCacheEntry newEntry = new HtmlCacheEntry(hashCode, new Date(DateTime.now().getMillis()), data, ttl); try { Log.d(TAG, "put: writing entry: " + newEntry); return getDao().create(newEntry) == 1; } catch (SQLException e) { Log.e(TAG, "put: ", e); return false; } } public boolean remove(final String url) { final int hashCode = url.hashCode(); HtmlCacheEntry entry = retrieve(hashCode); if (entry != null) { Log.d(TAG, "remove: removing entry: " + entry); return remove(entry); } else { Log.d(TAG, "remove: entry does not exist"); return false; } } private boolean remove(HtmlCacheEntry entry) { try { return getDao().delete(entry) == 1; } catch (SQLException e) { Log.e(TAG, "remove: ", e); return false; } } private void clearCache() { try { for (HtmlCacheEntry entry : getDao().queryForAll()) { remove(entry); } } catch (SQLException e) { Log.e(TAG, "clearCache: ", e); } } /** * Removes all invalid entries from cache. * * @return number of removed entries */ public Integer purgeCache() { try { Integer count = (Integer) DB.transaction(new Callable<Integer>() { @Override public Integer call() throws Exception { Integer count = 0; CloseableIterator<HtmlCacheEntry> iterator = getDao().iterator(); while (iterator.hasNext()) { HtmlCacheEntry entry = iterator.nextThrow(); if (!checkTtl(entry)) remove(entry); count++; } iterator.close(); return count; } }); Log.v(TAG, "purgeCache: purged " + count + " entries"); return count; } catch (Exception e) { return -1; } } private Dao<HtmlCacheEntry, Long> getDao() { if (dao == null) dao = new HtmlCacheDAO(DB.helper()).getConcreteDao(); return dao; } }