package org.bitseal.database;
import java.util.ArrayList;
import org.bitseal.data.QueueRecord;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
/**
* A singleton class which controls the creation, reading, updating, and
* deletion of stored QueueRecord objects.
*
* @author Jonathan Coe
*/
public class QueueRecordProvider
{
private static final String TAG = "QUEUE_RECORD_PROVIDER";
private static QueueRecordProvider sQueueRecordProvider;
private Context mAppContext;
private static ContentResolver mContentResolver;
private QueueRecordProvider(Context appContext)
{
mAppContext = appContext;
mContentResolver = mAppContext.getContentResolver();
}
/**
* Returns an instance of this singleton class.
*
* @param c - A Context object for the currently running application
*/
public static QueueRecordProvider get(Context c)
{
if (sQueueRecordProvider == null)
{
Context appContext = c.getApplicationContext();
sQueueRecordProvider = new QueueRecordProvider(appContext);
}
return sQueueRecordProvider;
}
/**
* Takes an QueueRecord object and adds it to the app's
* SQLite database as a new record, returning the ID of the
* newly created record.
*
* @param q - The QueueRecord object to be added
*
* @return id - A long value representing the ID of the newly
* created record
*/
public long addQueueRecord(QueueRecord q)
{
ContentValues values = new ContentValues();
values.put(QueueRecordsTable.COLUMN_TASK, q.getTask());
values.put(QueueRecordsTable.COLUMN_TRIGGER_TIME, q.getTriggerTime());
values.put(QueueRecordsTable.COLUMN_RECORD_COUNT, q.getRecordCount());
values.put(QueueRecordsTable.COLUMN_LAST_ATTEMPT_TIME, q.getLastAttemptTime());
values.put(QueueRecordsTable.COLUMN_ATTEMPTS, q.getAttempts());
values.put(QueueRecordsTable.COLUMN_OBJECT_0_ID, q.getObject0Id());
values.put(QueueRecordsTable.COLUMN_OBJECT_0_TYPE, q.getObject0Type());
values.put(QueueRecordsTable.COLUMN_OBJECT_1_ID, q.getObject1Id());
values.put(QueueRecordsTable.COLUMN_OBJECT_1_TYPE, q.getObject1Type());
values.put(QueueRecordsTable.COLUMN_OBJECT_2_ID, q.getObject2Id());
values.put(QueueRecordsTable.COLUMN_OBJECT_2_TYPE, q.getObject2Type());
Uri insertionUri = mContentResolver.insert(DatabaseContentProvider.CONTENT_URI_QUEUE_RECORDS, values);
Log.i(TAG, "QueueRecord with task " + q.getTask() + " and number of attempts " + q.getAttempts() + " saved to database");
// Parse the ID of the newly created record from the insertion URI
String uriString = insertionUri.toString();
String idString = uriString.substring(uriString.indexOf("/") + 1);
long id = Long.parseLong(idString);
return id;
}
/**
* Finds all QueueRecords in the application's database that match the given field
*
* @param columnName - A String specifying the name of the column in the database that
* should be used to find matching records. See the QueueRecordsTable class to find
* the relevant column name.
* @param searchString - A String specifying the value to search for. There are 4 use cases
* for this:<br>
* 1) The value to search for is a String (e.g. A label from the UI). In this case the value
* can be passed in directly.<br>
* 2) The value to search for is an int or long. In this case you should use String.valueOf(x)
* and pass in the resulting String.<br>
* 3) The value to search for is a boolean. In this case you should pass in the String "0" for
* false or the String "1" for true. <br>
* 4) The value to search for is a byte[]. In this case you should encode the byte[] into a
* Base64 encoded String using the class android.util.Base64 and pass in the resulting String.<br><br>
*
* <b>NOTE:</b> The above String conversion is very clumsy, but seems to be necessary. See
* https://stackoverflow.com/questions/20911760/android-how-to-query-sqlitedatabase-with-non-string-selection-args
*
* @return An ArrayList containing QueueRecord objects populated with the data from
* the database search
*/
public ArrayList<QueueRecord> searchQueueRecords(String columnName, String searchString)
{
ArrayList<QueueRecord> matchingRecords = new ArrayList<QueueRecord>();
// Specify which columns from the table we are interested in
String[] projection = {
QueueRecordsTable.COLUMN_ID,
QueueRecordsTable.COLUMN_TASK,
QueueRecordsTable.COLUMN_TRIGGER_TIME,
QueueRecordsTable.COLUMN_RECORD_COUNT,
QueueRecordsTable.COLUMN_LAST_ATTEMPT_TIME,
QueueRecordsTable.COLUMN_ATTEMPTS,
QueueRecordsTable.COLUMN_OBJECT_0_ID,
QueueRecordsTable.COLUMN_OBJECT_0_TYPE,
QueueRecordsTable.COLUMN_OBJECT_1_ID,
QueueRecordsTable.COLUMN_OBJECT_1_TYPE,
QueueRecordsTable.COLUMN_OBJECT_2_ID,
QueueRecordsTable.COLUMN_OBJECT_2_TYPE};
// Query the database via the ContentProvider
Cursor cursor = mContentResolver.query(
DatabaseContentProvider.CONTENT_URI_QUEUE_RECORDS,
projection,
QueueRecordsTable.TABLE_QUEUE_RECORDS + "." + columnName + " = ? ",
new String[]{searchString},
null);
if (cursor.moveToFirst())
{
do
{
long id = cursor.getLong(0);
String task = cursor.getString(1);
long triggerTime = cursor.getLong(2);
int completionCount = cursor.getInt(3);
long lastAttemptTime = cursor.getLong(4);
int attempts = cursor.getInt(5);
long object0Id = cursor.getLong(6);
String object0Type = cursor.getString(7);
long object1Id = cursor.getLong(8);
String object1Type = cursor.getString(9);
long object2Id = cursor.getLong(10);
String object2Type = cursor.getString(11);
QueueRecord q = new QueueRecord();
q.setId(id);
q.setTask(task);
q.setTriggerTime(triggerTime);
q.setRecordCount(completionCount);
q.setLastAttemptTime(lastAttemptTime);
q.setAttempts(attempts);
q.setObject0Id(object0Id);
q.setObject0Type(object0Type);
q.setObject1Id(object1Id);
q.setObject1Type(object1Type);
q.setObject2Id(object2Id);
q.setObject2Type(object2Type);
matchingRecords.add(q);
}
while (cursor.moveToNext());
}
else
{
Log.i(TAG, "Unable to find any QueueRecords with the value " + searchString + " in the " + columnName + " column");
cursor.close();
return matchingRecords;
}
cursor.close();
return matchingRecords;
}
/**
* Searches the database for the QueueRecord with the given ID.
* This method will return exactly one QueueRecord object or throw
* a RuntimeException.
*
* @param id - A long value representing the QueueRecord's ID.
*
* @return The QueueRecord object with the given ID.
*/
public QueueRecord searchForSingleRecord(long id)
{
ArrayList<QueueRecord> retrievedRecords = searchQueueRecords(QueueRecordsTable.COLUMN_ID, String.valueOf(id));
if (retrievedRecords.size() != 1)
{
throw new RuntimeException("There should be exactly 1 record found in this search. Instead " + retrievedRecords.size() + " records were found");
}
else
{
return retrievedRecords.get(0);
}
}
/**
* Returns an ArrayList containing all the QueueRecords stored in the
* application's database
*
* @return An ArrayList containing one QueueRecord object for
* each record in the QueueRecords table.
*/
public ArrayList<QueueRecord> getAllQueueRecords()
{
ArrayList<QueueRecord> queueRecords = new ArrayList<QueueRecord>();
// Specify which columns from the table we are interested in
String[] projection = {
QueueRecordsTable.COLUMN_ID,
QueueRecordsTable.COLUMN_TASK,
QueueRecordsTable.COLUMN_TRIGGER_TIME,
QueueRecordsTable.COLUMN_RECORD_COUNT,
QueueRecordsTable.COLUMN_LAST_ATTEMPT_TIME,
QueueRecordsTable.COLUMN_ATTEMPTS,
QueueRecordsTable.COLUMN_OBJECT_0_ID,
QueueRecordsTable.COLUMN_OBJECT_0_TYPE,
QueueRecordsTable.COLUMN_OBJECT_1_ID,
QueueRecordsTable.COLUMN_OBJECT_1_TYPE,
QueueRecordsTable.COLUMN_OBJECT_2_ID,
QueueRecordsTable.COLUMN_OBJECT_2_TYPE};
// Query the database via the ContentProvider
Cursor cursor = mContentResolver.query(
DatabaseContentProvider.CONTENT_URI_QUEUE_RECORDS,
projection,
null,
null,
null);
if (cursor.moveToFirst())
{
do
{
long id = cursor.getLong(0);
String task = cursor.getString(1);
long triggerTime = cursor.getLong(2);
int completionCount = cursor.getInt(3);
long lastAttemptTime = cursor.getLong(4);
int attempts = cursor.getInt(5);
long object0Id = cursor.getLong(6);
String object0Type = cursor.getString(7);
long object1Id = cursor.getLong(8);
String object1Type = cursor.getString(9);
long object2Id = cursor.getLong(10);
String object2Type = cursor.getString(11);
QueueRecord q = new QueueRecord();
q.setId(id);
q.setTask(task);
q.setTriggerTime(triggerTime);
q.setRecordCount(completionCount);
q.setLastAttemptTime(lastAttemptTime);
q.setAttempts(attempts);
q.setObject0Id(object0Id);
q.setObject0Type(object0Type);
q.setObject1Id(object1Id);
q.setObject1Type(object1Type);
q.setObject2Id(object2Id);
q.setObject2Type(object2Type);
queueRecords.add(q);
}
while (cursor.moveToNext());
}
cursor.close();
return queueRecords;
}
/**
* Updates the database record for a given QueueRecord object<br><br>
*
* <b>NOTE:</b> This method uses the given QueueRecord's ID field to determine
* which record in the database to update
*
* @param q - The QueueRecord object to be updated
*/
public void updateQueueRecord(QueueRecord q)
{
ContentValues values = new ContentValues();
values.put(QueueRecordsTable.COLUMN_TASK, q.getTask());
values.put(QueueRecordsTable.COLUMN_TRIGGER_TIME, q.getTriggerTime());
values.put(QueueRecordsTable.COLUMN_RECORD_COUNT, q.getRecordCount());
values.put(QueueRecordsTable.COLUMN_LAST_ATTEMPT_TIME, q.getLastAttemptTime());
values.put(QueueRecordsTable.COLUMN_ATTEMPTS, q.getAttempts());
values.put(QueueRecordsTable.COLUMN_OBJECT_0_ID, q.getObject0Id());
values.put(QueueRecordsTable.COLUMN_OBJECT_0_TYPE, q.getObject0Type());
values.put(QueueRecordsTable.COLUMN_OBJECT_1_ID, q.getObject1Id());
values.put(QueueRecordsTable.COLUMN_OBJECT_1_TYPE, q.getObject1Type());
values.put(QueueRecordsTable.COLUMN_OBJECT_2_ID, q.getObject2Id());
values.put(QueueRecordsTable.COLUMN_OBJECT_2_TYPE, q.getObject2Type());
long id = q.getId();
String task = q.getTask();
int attempts = q.getAttempts();
// Query the database via the ContentProvider and update the record with the matching ID
mContentResolver.update(DatabaseContentProvider.CONTENT_URI_QUEUE_RECORDS,
values,
QueueRecordsTable.COLUMN_ID + " = ? ",
new String[]{String.valueOf(id)});
Log.i(TAG, "QueueRecord with ID " + id + ", task '" + task + "', and number of attempts " + attempts + " updated");
}
/**
* Deletes a QueueRecord object from the application's SQLite database<br><br>
*
* <b>NOTE:</b> This method uses the given QueueRecord's ID field to determine
* which record in the database to delete
*
* @param m - The QueueRecord object to be deleted
*/
public void deleteQueueRecord(QueueRecord q)
{
long id = q.getId();
// Query the database via the ContentProvider and delete the record with the matching ID
int recordsDeleted = mContentResolver.delete(
DatabaseContentProvider.CONTENT_URI_QUEUE_RECORDS,
QueueRecordsTable.COLUMN_ID + " = ? ",
new String[]{String.valueOf(id)});
Log.i(TAG, recordsDeleted + " QueueRecord(s) with task " + q.getTask() + " and number of attempts " + q.getAttempts() +
" deleted from the database.");
}
/**
* Deletes all QueueRecords from the database
*/
public void deleteAllQueueRecords()
{
// Query the database via the ContentProvider and delete all the records
int recordsDeleted = mContentResolver.delete(
DatabaseContentProvider.CONTENT_URI_QUEUE_RECORDS,
null,
null);
Log.i(TAG, "All QueueRecords deleted deleted from the database. Total number deleted: " + recordsDeleted);
}
}