package org.liberty.android.fantastischmemo.common;
import android.content.Context;
import android.util.Log;
import com.j256.ormlite.dao.DaoManager;
import org.apache.commons.io.FilenameUtils;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantLock;
/*
* Keep the reference count of each AnyMemoDBOpenHelper.
*/
public class AnyMemoDBOpenHelperManager {
private static final String TAG = AnyMemoDBOpenHelperManager.class.getSimpleName();
// Comparator for determining if two files are the same
private static Comparator<String> filenameComparator = new Comparator<String>() {
@Override
public int compare(String lhs, String rhs) {
if (FilenameUtils.equalsNormalizedOnSystem(lhs, rhs)) {
return 0;
} else {
return lhs.compareTo(rhs);
}
}
};
private static volatile Map<String, WeakReference<AnyMemoDBOpenHelper>> helpers = Collections.synchronizedMap(new TreeMap<String, WeakReference<AnyMemoDBOpenHelper>>(filenameComparator));
private static volatile Map<String, Integer> refCounts = Collections.synchronizedMap(new TreeMap<String, Integer>(filenameComparator));
/* Used to synchronize different method, i. e. creating and releasing helper. */
private static volatile ReentrantLock bigLock = new ReentrantLock();
/**
* Get a DBOpenHelper with application context.
*/
public static AnyMemoDBOpenHelper getHelper(String dbpath) {
return getHelper(AMApplication.getCurrentApplicationContext(), dbpath);
}
/* Get a db open helper and return a cached one if it was called before for the same db */
public static AnyMemoDBOpenHelper getHelper(Context context, String dbpath) {
bigLock.lock();
try {
assert dbpath != null : "dbpath should not be null";
if (!helpers.containsKey(dbpath)) {
Log.i(TAG, "Call get AnyMemoDBOpenHelper for first time for db: " + dbpath);
AnyMemoDBOpenHelper helper = new AnyMemoDBOpenHelper(context, dbpath);
helpers.put(dbpath, new WeakReference<AnyMemoDBOpenHelper>(helper));
refCounts.put(dbpath, 1);
return helpers.get(dbpath).get();
} else {
Log.i(TAG, "Call get AnyMemoDBOpenHelper for " + dbpath + " again, return existing helper.");
refCounts.put(dbpath, refCounts.get(dbpath) + 1);
return helpers.get(dbpath).get();
}
} finally {
bigLock.unlock();
}
}
/* Release a db open helper if there is no open connection to it */
public static void releaseHelper(AnyMemoDBOpenHelper helper) {
bigLock.lock();
try {
String dbpath = helper.getDbPath();
if (!helpers.containsKey(dbpath)) {
Log.w(TAG, "Release a wrong db path or release an already been released helper!");
return;
}
Log.i(TAG, "Release AnyMemoDBOpenHelper: " + dbpath + " Ref count: " + refCounts.get(dbpath));
refCounts.put(dbpath, refCounts.get(dbpath) - 1);
if (refCounts.get(dbpath) == 0) {
helper.close();
DaoManager.clearCache();
DaoManager.clearDaoCache();
helpers.remove(dbpath);
Log.i(TAG, "All connection released. Close helper. DB: " + dbpath);
}
} finally {
bigLock.unlock();
}
}
public static void forceRelease(String dbpath) {
bigLock.lock();
try {
if (!helpers.containsKey(dbpath)) {
Log.w(TAG, "Force release a file that is not opened yet. Do nothing");
return;
}
AnyMemoDBOpenHelper helper = helpers.get(dbpath).get();
Log.i(TAG, "force releasing " + dbpath + " It contains " + refCounts.get(dbpath) + " refs");
// Weak reference can return null, so we must check here.
if (helper != null) {
helper.close();
} else {
Log.w(TAG, "forceRelease a path that has already been released by GC.");
}
DaoManager.clearCache();
DaoManager.clearDaoCache();
helpers.remove(dbpath);
refCounts.get(dbpath);
Log.i(TAG, "Force released a db file. DB: " + dbpath);
} finally {
bigLock.unlock();
}
}
}