/**
Copyright 2015 Tim Engler, Rareventure LLC
This file is part of Tiny Travel Tracker.
Tiny Travel Tracker is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Tiny Travel Tracker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tiny Travel Tracker. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rareventure.android.database;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import com.rareventure.android.DbUtil;
import com.rareventure.android.Util;
import com.rareventure.android.encryption.EncryptedRow;
import com.rareventure.gps2.GTG;
import com.rareventure.gps2.database.TAssert;
import com.rareventure.util.Pair;
public class DbDatastoreAccessor<T extends EncryptedRow> implements Cache.DatastoreAccessor<T> {
private TableInfo tableInfo;
public static final String[] COLUMNS = new String [] { /* ttt_installer:obfuscate_str */"_ID",
/* ttt_installer:obfuscate_str */"USER_DATA_KEY_FK",
/* ttt_installer:obfuscate_str */"DATA" };
private static final String INSERT_STMT = /* ttt_installer:obfuscate_str */"insert into ${table} (_ID, USER_DATA_KEY_FK, DATA) " +
/* ttt_installer:obfuscate_str */"values (?,?,?)";
private static final String UPDATE_STMT = /* ttt_installer:obfuscate_str */"update ${table} set USER_DATA_KEY_FK = ?, DATA = ? where _ID = ?";
private byte [] retrieveRowData;
private byte [] writeRowData;
public DbDatastoreAccessor(TableInfo ti)
{
this.tableInfo = ti;
}
@Override
public int getNextRowId() {
return (int) DbUtil.runQuery(GTG.db, "select max(_id) from "+ tableInfo.tableName)+1;
}
@Override
public synchronized void updateRow(T row) {
if(row.id == -1)
TAssert.fail();
if(writeRowData == null)
{
writeRowData = new byte[GTG.crypt.crypt
.getNumOutputBytesForEncryption(row.data2.length)];
}
byte [] encryptedData = row.encryptRow(writeRowData);
SQLiteStatement s = DbUtil.createOrGetStatement(GTG.db, tableInfo.updateStatementStr);
s.bindLong(1, GTG.crypt.userDataKeyId);
s.bindBlob(2, encryptedData);
s.bindLong(3, row.id);
// doExtraUpdateBinds(s);
s.execute();
}
/**
* Inserts a row. encryptedData and userDataKeyFk must already be set up.
* id will be set
*
* @param db
*/
@Override
public synchronized void insertRow(T row) {
if(writeRowData == null)
{
writeRowData = new byte[GTG.crypt.crypt
.getNumOutputBytesForEncryption(row.data2.length)];
}
byte [] encryptedData = row.encryptRow(writeRowData);
SQLiteStatement s = DbUtil.createOrGetStatement(GTG.db, tableInfo.insertStatementStr);
s.bindLong(1, row.id);
s.bindLong(2, GTG.crypt.userDataKeyId);
s.bindBlob(3, encryptedData);
// doExtraInsertBinds(s);
row.id = (int) s.executeInsert();
}
@Override
public synchronized boolean getRow(T outRow, int id) {
//believe it or not, there is no way to cache a query that uses a cursor (which is necessary if you want
//to select multiple rows or even multiple columns)
Cursor c = GTG.db.query(tableInfo.tableName, COLUMNS, "_id = ?", new String [] { String.valueOf(id) }, null, null, null);
try {
if(!c.moveToNext())
{
return false;
}
readRow(outRow, c);
}
finally
{
DbUtil.closeCursors(c);
}
return true;
}
public void readRow(T row, Cursor c) {
row.id = c.getInt(0);
int userDataKeyFk = c.getInt(1);
byte [] encryptedData = c.getBlob(2);
row.decryptRow(userDataKeyFk, encryptedData);
}
public static String createInsertStatement(String tableName)
{
return Util.varReplace(INSERT_STMT, "table", tableName);
}
public static String createUpdateStatement(String tableName)
{
return Util.varReplace(UPDATE_STMT, "table", tableName);
}
public static String createDeleteStatement(String tableName) {
return "delete from "+tableName+" where _id = ?;";
}
public void deleteRow(int id) {
SQLiteStatement s = DbUtil.createOrGetStatement(GTG.db,
tableInfo.deleteStatementStr);
s.bindLong(1, id);
s.execute();
}
public Cursor query(String where, String orderBy, String ... whereData) {
return GTG.db.query(tableInfo.tableName, COLUMNS, where, whereData, null, null, orderBy);
}
public void deleteRow(Cursor c) {
deleteRow(c.getInt(0));
}
@Override
public void softUpdateRow(T row) {
throw new IllegalStateException("Soft update not needed");
}
@Override
public boolean needsSoftUpdate() {
return false;
}
}