/*
* Copyright 2015-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Amazon.MobileAnalytics.Model;
using ThirdParty.Json.LitJson;
using Amazon.MobileAnalytics.MobileAnalyticsManager;
using Amazon.Util;
using Amazon.Runtime.Internal.Util;
using Amazon.Util.Internal;
using System.Globalization;
using System.Data.SQLite;
namespace Amazon.MobileAnalytics.MobileAnalyticsManager.Internal
{
///
/// Implementation of .
/// The object stores Mobile Analytic events in SQLite database.
///
public partial class SQLiteEventStore : IEventStore
{
///
/// Implements the Dispose pattern
///
/// Whether this object is being disposed via a call to Dispose
/// or garbage collected.
protected virtual void Dispose(bool disposing)
{
}
///
/// Sets up SQLite database.
///
private void SetupSQLiteEventStore()
{
this.DBfileFullPath = InternalSDKUtils.DetermineAppLocalStoragePath(dbFileName);
string vacuumCommand = "PRAGMA auto_vacuum = 1";
string sqlCommand = string.Format(CultureInfo.InvariantCulture, "CREATE TABLE IF NOT EXISTS {0} ({1} TEXT NOT NULL,{2} TEXT NOT NULL UNIQUE,{3} TEXT NOT NULL, {4} INTEGER NOT NULL DEFAULT 0 )",
TABLE_NAME, EVENT_COLUMN_NAME, EVENT_ID_COLUMN_NAME, MA_APP_ID_COLUMN_NAME, EVENT_DELIVERY_ATTEMPT_COUNT_COLUMN_NAME);
lock (_lock)
{
using (var connection = new SQLiteConnection("Data Source=" + this.DBfileFullPath + ";Version=3;"))
{
try
{
if (!File.Exists(this.DBfileFullPath))
{
string directory = Path.GetDirectoryName(this.DBfileFullPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
SQLiteConnection.CreateFile(this.DBfileFullPath);
}
connection.Open();
using (var command = new SQLiteCommand(vacuumCommand, connection))
{
command.ExecuteNonQuery();
}
using (var command = new SQLiteCommand(sqlCommand, connection))
{
command.ExecuteNonQuery();
}
}
finally
{
if (null != connection)
connection.Close();
}
}
}
}
///
/// Add an event to the store.
///
/// Amazon Mobile Analytics event in string.
/// Amazon Mobile Analytics App ID.
[System.Security.SecuritySafeCritical]
public void PutEvent(string eventString, string appID)
{
long currentDatabaseSize = this.DatabaseSize;
if (currentDatabaseSize >= _maConfig.MaxDBSize)
{
InvalidOperationException e = new InvalidOperationException();
_logger.Error(e, "The database size has exceeded the threshold limit. Unable to insert any new events");
}
else if ((double)currentDatabaseSize / (double)_maConfig.MaxDBSize >= _maConfig.DBWarningThreshold)
{
_logger.InfoFormat("The database size is almost full");
}
else
{
string sqlCommand = string.Format(CultureInfo.InvariantCulture, "INSERT INTO {0} ({1},{2},{3}) values(@event,@id,@appID)", TABLE_NAME, EVENT_COLUMN_NAME, EVENT_ID_COLUMN_NAME, MA_APP_ID_COLUMN_NAME);
lock (_lock)
{
using (var connection = new SQLiteConnection("Data Source=" + this.DBfileFullPath + ";Version=3;"))
{
try
{
connection.Open();
using (var command = new SQLiteCommand(sqlCommand, connection))
{
command.Parameters.Add(new SQLiteParameter("@event", eventString));
command.Parameters.Add(new SQLiteParameter("@id", Guid.NewGuid().ToString()));
command.Parameters.Add(new SQLiteParameter("@appID", appID));
command.ExecuteNonQuery();
}
}
finally
{
if (null != connection)
connection.Close();
}
}
}
}
}
///
/// Deletes a list of events.
///
/// List of row identifiers.
[System.Security.SecuritySafeCritical]
public void DeleteEvent(List rowIds)
{
string ids = string.Format(CultureInfo.InvariantCulture, "'{0}'", string.Join("', '", rowIds.ToArray()));
string sqlCommand = string.Format(CultureInfo.InvariantCulture, "DELETE FROM {0} WHERE {1} IN ({2})", TABLE_NAME, EVENT_ID_COLUMN_NAME, ids);
SQLiteConnection connection = null;
lock (_lock)
{
using (connection = new SQLiteConnection("Data Source=" + this.DBfileFullPath + ";Version=3;"))
{
try
{
connection.Open();
using (var command = new SQLiteCommand(sqlCommand, connection))
{
command.ExecuteNonQuery();
}
}
finally
{
if (null != connection)
connection.Close();
}
}
}
}
///
/// Get events from the Event Store
///
/// Amazon Mobile Analytics App Id.
/// Max number of events is allowed to return.
/// The events as a List of .
[System.Security.SecuritySafeCritical]
public List GetEvents(string appID, int maxAllowed)
{
List eventList = new List();
string sqlCommand = string.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE {1} = @appID ORDER BY {2}, ROWID LIMIT {3} ", TABLE_NAME, MA_APP_ID_COLUMN_NAME, EVENT_DELIVERY_ATTEMPT_COUNT_COLUMN_NAME, maxAllowed);
lock (_lock)
{
using (var connection = new SQLiteConnection("Data Source=" + this.DBfileFullPath + ";Version=3;"))
{
try
{
connection.Open();
using (var command = new SQLiteCommand(sqlCommand, connection))
{
command.Parameters.Add(new SQLiteParameter("@appID", appID));
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
JsonData data = new JsonData();
data["id"] = reader[EVENT_ID_COLUMN_NAME].ToString();
data["event"] = reader[EVENT_COLUMN_NAME.ToUpperInvariant()].ToString();
data["appID"] = reader[MA_APP_ID_COLUMN_NAME].ToString();
eventList.Add(data);
}
}
}
}
finally
{
if (null != connection)
connection.Close();
}
}
}
return eventList;
}
///
/// Gets Numbers the of events.
///
/// Amazon Mobile Analytics App Identifier.
/// The number of events.
[System.Security.SecuritySafeCritical]
public long NumberOfEvents(string appID)
{
long count = 0;
string sqlCommand = string.Format(CultureInfo.InvariantCulture, "SELECT COUNT(*) C FROM {0} where {1} = @appID", TABLE_NAME, MA_APP_ID_COLUMN_NAME);
using (var connection = new SQLiteConnection("Data Source=" + this.DBfileFullPath + ";Version=3;"))
{
try
{
connection.Open();
using (var command = new SQLiteCommand(sqlCommand, connection))
{
command.Parameters.Add(new SQLiteParameter("@appID", appID));
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
count = (long)reader["C"];
}
}
}
}
finally
{
if (null != connection)
connection.Close();
}
}
return count;
}
///
/// Gets the size of the database.
///
/// The database size.
public long DatabaseSize
{
get
{
FileInfo fileInfo = new FileInfo(this.DBfileFullPath);
return fileInfo.Length;
}
}
}
}