/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.repositories.android;
import org.mozilla.gecko.sync.Logger;
import org.mozilla.gecko.sync.repositories.NullCursorException;
import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class ClientsDatabase extends CachedSQLiteOpenHelper {
public static final String LOG_TAG = "ClientsDatabase";
// Database Specifications.
protected static final String DB_NAME = "clients_database";
protected static final int SCHEMA_VERSION = 2;
// Clients Table.
public static final String TBL_CLIENTS = "clients";
public static final String COL_ACCOUNT_GUID = "guid";
public static final String COL_PROFILE = "profile";
public static final String COL_NAME = "name";
public static final String COL_TYPE = "device_type";
public static final String[] TBL_CLIENTS_COLUMNS = new String[] { COL_ACCOUNT_GUID, COL_PROFILE, COL_NAME, COL_TYPE };
public static final String TBL_CLIENTS_KEY = COL_ACCOUNT_GUID + " = ? AND " +
COL_PROFILE + " = ?";
// Commands Table.
public static final String TBL_COMMANDS = "commands";
public static final String COL_COMMAND = "command";
public static final String COL_ARGS = "args";
public static final String[] TBL_COMMANDS_COLUMNS = new String[] { COL_ACCOUNT_GUID, COL_COMMAND, COL_ARGS };
public static final String TBL_COMMANDS_KEY = COL_ACCOUNT_GUID + " = ? AND " +
COL_COMMAND + " = ? AND " +
COL_ARGS + " = ?";
public static final String TBL_COMMANDS_GUID_QUERY = COL_ACCOUNT_GUID + " = ? ";
private final RepoUtils.QueryHelper queryHelper;
public ClientsDatabase(Context context) {
super(context, DB_NAME, null, SCHEMA_VERSION);
this.queryHelper = new RepoUtils.QueryHelper(context, null, LOG_TAG);
Logger.debug(LOG_TAG, "ClientsDatabase instantiated.");
}
@Override
public void onCreate(SQLiteDatabase db) {
Logger.debug(LOG_TAG, "ClientsDatabase.onCreate().");
createClientsTable(db);
createCommandsTable(db);
}
public static void createClientsTable(SQLiteDatabase db) {
Logger.debug(LOG_TAG, "ClientsDatabase.createClientsTable().");
String createClientsTableSql = "CREATE TABLE " + TBL_CLIENTS + " ("
+ COL_ACCOUNT_GUID + " TEXT, "
+ COL_PROFILE + " TEXT, "
+ COL_NAME + " TEXT, "
+ COL_TYPE + " TEXT, "
+ "PRIMARY KEY (" + COL_ACCOUNT_GUID + ", " + COL_PROFILE + "))";
db.execSQL(createClientsTableSql);
}
public static void createCommandsTable(SQLiteDatabase db) {
Logger.debug(LOG_TAG, "ClientsDatabase.createCommandsTable().");
String createCommandsTableSql = "CREATE TABLE " + TBL_COMMANDS + " ("
+ COL_ACCOUNT_GUID + " TEXT, "
+ COL_COMMAND + " TEXT, "
+ COL_ARGS + " TEXT, "
+ "PRIMARY KEY (" + COL_ACCOUNT_GUID + ", " + COL_COMMAND + ", " + COL_ARGS + "), "
+ "FOREIGN KEY (" + COL_ACCOUNT_GUID + ") REFERENCES " + TBL_CLIENTS + " (" + COL_ACCOUNT_GUID + "))";
db.execSQL(createCommandsTableSql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Logger.debug(LOG_TAG, "ClientsDatabase.onUpgrade().");
// For now we'll just drop and recreate the tables.
db.execSQL("DROP TABLE IF EXISTS " + TBL_CLIENTS);
db.execSQL("DROP TABLE IF EXISTS " + TBL_COMMANDS);
onCreate(db);
}
public void wipeDB() {
SQLiteDatabase db = this.getCachedWritableDatabase();
onUpgrade(db, SCHEMA_VERSION, SCHEMA_VERSION);
}
public void wipeClientsTable() {
SQLiteDatabase db = this.getCachedWritableDatabase();
db.execSQL("DELETE FROM " + TBL_CLIENTS);
}
public void wipeCommandsTable() {
SQLiteDatabase db = this.getCachedWritableDatabase();
db.execSQL("DELETE FROM " + TBL_COMMANDS);
}
// If a record with given GUID exists, we'll update it,
// otherwise we'll insert it.
public void store(String profileId, ClientRecord record) {
SQLiteDatabase db = this.getCachedWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(COL_ACCOUNT_GUID, record.guid);
cv.put(COL_PROFILE, profileId);
cv.put(COL_NAME, record.name);
cv.put(COL_TYPE, record.type);
String[] args = new String[] { record.guid, profileId };
int rowsUpdated = db.update(TBL_CLIENTS, cv, TBL_CLIENTS_KEY, args);
if (rowsUpdated >= 1) {
Logger.debug(LOG_TAG, "Replaced client record for row with accountGUID " + record.guid);
} else {
long rowId = db.insert(TBL_CLIENTS, null, cv);
Logger.debug(LOG_TAG, "Inserted client record into row: " + rowId);
}
}
/**
* Store a command in the commands database if it doesn't already exist.
*
* @param accountGUID
* @param command - The command type
* @param args - A JSON string of args
* @throws NullCursorException
*/
public void store(String accountGUID, String command, String args) throws NullCursorException {
if (Logger.LOG_PERSONAL_INFORMATION) {
Logger.pii(LOG_TAG, "Storing command " + command + " with args " + args);
} else {
Logger.trace(LOG_TAG, "Storing command " + command + ".");
}
SQLiteDatabase db = this.getCachedWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(COL_ACCOUNT_GUID, accountGUID);
cv.put(COL_COMMAND, command);
if (args == null) {
cv.put(COL_ARGS, "[]");
} else {
cv.put(COL_ARGS, args);
}
Cursor cur = this.fetchSpecificCommand(accountGUID, command, args);
try {
if (cur.moveToFirst()) {
Logger.debug(LOG_TAG, "Command already exists in database.");
return;
}
} finally {
cur.close();
}
long rowId = db.insert(TBL_COMMANDS, null, cv);
Logger.debug(LOG_TAG, "Inserted command into row: " + rowId);
}
public Cursor fetchClientsCursor(String accountGUID, String profileId) throws NullCursorException {
String[] args = new String[] { accountGUID, profileId };
SQLiteDatabase db = this.getCachedReadableDatabase();
return queryHelper.safeQuery(db, ".fetchClientsCursor", TBL_CLIENTS, TBL_CLIENTS_COLUMNS, TBL_CLIENTS_KEY, args);
}
public Cursor fetchSpecificCommand(String accountGUID, String command, String commandArgs) throws NullCursorException {
String[] args = new String[] { accountGUID, command, commandArgs };
SQLiteDatabase db = this.getCachedReadableDatabase();
return queryHelper.safeQuery(db, ".fetchSpecificCommand", TBL_COMMANDS, TBL_COMMANDS_COLUMNS, TBL_COMMANDS_KEY, args);
}
public Cursor fetchCommandsForClient(String accountGUID) throws NullCursorException {
String[] args = new String[] { accountGUID };
SQLiteDatabase db = this.getCachedReadableDatabase();
return queryHelper.safeQuery(db, ".fetchCommandsForClient", TBL_COMMANDS, TBL_COMMANDS_COLUMNS, TBL_COMMANDS_GUID_QUERY, args);
}
public Cursor fetchAllClients() throws NullCursorException {
SQLiteDatabase db = this.getCachedReadableDatabase();
return queryHelper.safeQuery(db, ".fetchAllClients", TBL_CLIENTS, TBL_CLIENTS_COLUMNS, null, null);
}
public Cursor fetchAllCommands() throws NullCursorException {
SQLiteDatabase db = this.getCachedReadableDatabase();
return queryHelper.safeQuery(db, ".fetchAllCommands", TBL_COMMANDS, TBL_COMMANDS_COLUMNS, null, null);
}
public void deleteClient(String accountGUID, String profileId) {
String[] args = new String[] { accountGUID, profileId };
SQLiteDatabase db = this.getCachedWritableDatabase();
db.delete(TBL_CLIENTS, TBL_CLIENTS_KEY, args);
}
}