package pl.llp.aircasting.storage.db;
import pl.llp.aircasting.android.Logger;
import pl.llp.aircasting.util.Constants;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
import com.google.inject.Singleton;
@Singleton
public class AirCastingDB extends SQLiteOpenHelper implements DBConstants
{
private static volatile SQLiteDatabase db;
private static volatile Throwable lockedAt;
public AirCastingDB(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
new SchemaCreator().create(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
new SchemaMigrator().migrate(db, oldVersion, newVersion);
}
@Override
public synchronized SQLiteDatabase getWritableDatabase()
{
throw new RuntimeException("Don't use me!");
}
@Override
public synchronized SQLiteDatabase getReadableDatabase()
{
throw new RuntimeException("Don't use me!");
}
@VisibleForTesting
public SQLiteDatabase getDatabaseDuringTests()
{
return getDatabase();
}
private synchronized SQLiteDatabase getDatabase()
{
if(db == null || !db.isOpen())
{
db = super.getWritableDatabase();
lockedAt = new Throwable();
}
if(db.isDbLockedByOtherThreads())
{
Log.v("DATABASE!", "Database is locked: ", new Throwable());
Log.v("DATABASE!", "Locked at: ", lockedAt);
}
return db;
}
public synchronized <T> T executeWritableTask(WritableDatabaseTask<T> task)
{
SQLiteDatabase database = getDatabase();
T result;
database.beginTransaction();
try
{
result = catchError(task, database);
database.setTransactionSuccessful();
}
finally
{
database.endTransaction();
}
return result;
}
public synchronized <T> T executeReadOnlyTask(ReadOnlyDatabaseTask<T> task)
{
SQLiteDatabase database = getDatabase();
return catchError(task, database);
}
private <T> T catchError(DatabaseTask<T> task, SQLiteDatabase database)
{
T result = null;
try
{
result = measureExecution(task, database);
}
catch (Exception e)
{
Log.e(Constants.TAG, "Something bad happened", e);
}
return result;
}
private <T> T measureExecution(DatabaseTask<T> task, SQLiteDatabase database)
{
Stopwatch stopwatch = new Stopwatch().start();
T result = task.execute(database);
Logger.logDbPerformance("Database task took: " + stopwatch.elapsedMillis());
return result;
}
}