package com.cookpad.puree.storage; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.cookpad.puree.internal.ProcessName; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.text.TextUtils; import android.util.Log; import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.ParametersAreNonnullByDefault; @ParametersAreNonnullByDefault public class PureeSQLiteStorage extends SQLiteOpenHelper implements PureeStorage { private static final String DATABASE_NAME = "puree.db"; private static final String TABLE_NAME = "logs"; private static final String COLUMN_NAME_TYPE = "type"; private static final String COLUMN_NAME_LOG = "log"; private static final int DATABASE_VERSION = 1; private final JsonParser jsonParser = new JsonParser(); private final SQLiteDatabase db; private final AtomicBoolean lock = new AtomicBoolean(false); static String databaseName(Context context) { // do not share the database file in multi processes String processName = ProcessName.getAndroidProcessName(context); if (TextUtils.isEmpty(processName)) { return DATABASE_NAME; } else { return processName + "." + DATABASE_NAME; } } public PureeSQLiteStorage(Context context) { super(context, databaseName(context), null, DATABASE_VERSION); db = getWritableDatabase(); } public void insert(String type, JsonObject jsonLog) { ContentValues contentValues = new ContentValues(); contentValues.put(COLUMN_NAME_TYPE, type); contentValues.put(COLUMN_NAME_LOG, jsonLog.toString()); db.insert(TABLE_NAME, null, contentValues); } public Records select(String type, int logsPerRequest) { String query = "SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_NAME_TYPE + " = ?" + " ORDER BY id ASC" + " LIMIT " + logsPerRequest; Cursor cursor = db.rawQuery(query, new String[]{type}); try { return recordsFromCursor(cursor); } finally { cursor.close(); } } @Override public Records selectAll() { String query = "SELECT * FROM " + TABLE_NAME + " ORDER BY id ASC"; Cursor cursor = db.rawQuery(query, null); try { return recordsFromCursor(cursor); } finally { cursor.close(); } } private Records recordsFromCursor(Cursor cursor) { Records records = new Records(); while (cursor.moveToNext()) { Record record = buildRecord(cursor); records.add(record); } return records; } private Record buildRecord(Cursor cursor) { return new Record( cursor.getInt(0), cursor.getString(1), parseJsonString(cursor.getString(2))); } private int getRecordCount() { String query = "SELECT COUNT(*) FROM " + TABLE_NAME; Cursor cursor = db.rawQuery(query, null); int count = 0; if (cursor.moveToNext()) { count = cursor.getInt(0); } cursor.close(); return count; } private JsonObject parseJsonString(String jsonString) { return (JsonObject) jsonParser.parse(jsonString); } @Override public void delete(Records records) { String query = "DELETE FROM " + TABLE_NAME + " WHERE id IN (" + records.getIdsAsString() + ")"; db.execSQL(query); } @Override public void truncateBufferedLogs(int maxRecords) { int recordSize = getRecordCount(); if (recordSize > maxRecords) { String query = "DELETE FROM " + TABLE_NAME + " WHERE id IN ( SELECT id FROM " + TABLE_NAME + " ORDER BY id ASC LIMIT " + String.valueOf(recordSize - maxRecords) + ")"; db.execSQL(query); } } @Override public void clear() { String query = "DELETE FROM " + TABLE_NAME; db.execSQL(query); } @Override public void onCreate(SQLiteDatabase db) { String query = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_NAME_TYPE + " TEXT," + COLUMN_NAME_LOG + " TEXT" + ")"; db.execSQL(query); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.e("PureeDbHelper", "unexpected onUpgrade(db, " + oldVersion + ", " + newVersion + ")"); } @Override protected void finalize() throws Throwable { db.close(); super.finalize(); } @Override public boolean lock() { return lock.compareAndSet(false, true); } @Override public void unlock() { lock.set(false); } }