using System; using System.Data; using System.Globalization; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Text; using System.Threading; using System.Timers; using System.Diagnostics; namespace WmData { /// /// WmDataTransactionManager is the object that is responsible for /// registering and importing data transactions. /// Created 2nd of August 2010 /// public class WmDataTransactionManager { protected CultureInfo cultureInfoUs = null; protected WmGenericData data = null; protected WmIntermediateObjectManager intermediateObjectManager; protected System.Timers.Timer removeOldTransactionsTimer; protected int removeOldTransactionsAfterHours = 24; public WmDataTransactionManager(WmGenericData data) { cultureInfoUs = new CultureInfo("en-US"); this.data = data; intermediateObjectManager = data.IntermediateObjectManager; removeOldTransactionsTimer = new System.Timers.Timer(60000); removeOldTransactionsTimer.Elapsed += new ElapsedEventHandler(removeOldTransactionsTimer_Elapsed); removeOldTransactionsTimer.AutoReset = true; removeOldTransactionsTimer.Start(); } public void clearTransactions() { data.deleteTableContents(typeof(WmDataTransaction)); System.Diagnostics.Trace.WriteLine("WmDataTransactionManager: Cleared all transactions."); } protected void removeOldTransactionsTimer_Elapsed(object sender, ElapsedEventArgs e) { removeOldTransactionsTimer.Stop(); long removalLimitUtcTicks = DateTime.UtcNow.AddHours(-1 * removeOldTransactionsAfterHours).Ticks; string select = "localmomentutcticks<" + removalLimitUtcTicks; ArrayList tmpRes = data.getObjects(typeof(WmDataTransaction), select); WmDataTransaction[] oldTransactions = (WmDataTransaction[])tmpRes.ToArray(typeof(WmDataTransaction));; for (int t = 0; t < oldTransactions.Length; t++) { data.deleteObject(oldTransactions[t]); } if (oldTransactions.Length > 0) { System.Diagnostics.Trace.WriteLine("WmDataTransactionManager: Removed " + oldTransactions.Length + " old transaction(s)."); } removeOldTransactionsTimer.Start(); } public WmDataTransaction[] getTransactionsSince(long momentUtcTicks) { string select = "localmomentutcticks>" + momentUtcTicks; ArrayList tmpRes = data.getObjects(typeof(WmDataTransaction), select); tmpRes.Sort(); return (WmDataTransaction[])tmpRes.ToArray(typeof(WmDataTransaction)); } public DataRow[] getTransactionsAsDataRowsSince(long momentUtcTicks) { string select = "localmomentutcticks>" + momentUtcTicks; return data.getDataRows(typeof(WmDataTransaction), select, "localmomentutcticks ASC"); } public long getLastTransactionMomentUtcTicksOnTable(string tableName) { string select = "SELECT localmomentutcticks FROM " + data.SqlCatalogName + ".wmdatatransaction WHERE tablename='"+tableName+"' ORDER BY localmomentutcticks DESC LIMIT 1"; object value = data.getObjectFromSQL(select); long lastTransactionMomentTicksUtc = 0; if (value != null && !(value is DBNull)) { lastTransactionMomentTicksUtc = (long)value; } return lastTransactionMomentTicksUtc; } public void registerDeleteTransaction(string tableName, int rowId, long referenceTransactionMomentUtcTicks) { if (!tableName.Equals("wmdatatransaction")) { createTransactionObject(tableName, rowId, WmDataRowAction.DELETE, referenceTransactionMomentUtcTicks, null); } } public void registerInsertOrUpdateTransaction(string tableName, DataRow dataRow, WmDataRowAction dataRowAction, long referenceTransactionMomentUtcTicks) { if (!tableName.Equals("wmdatatransaction")) { // Step 1: Set culture to us english to make sure date time and numbers are always formatted correctly bool didChangeCulture = false; CultureInfo originalCultureInfo = Thread.CurrentThread.CurrentCulture; if (!Thread.CurrentThread.CurrentCulture.Name.Equals("en-US")) { Thread.CurrentThread.CurrentCulture = cultureInfoUs; } // Step 2: Create the Transaction object int rowId = (int)dataRow["id"]; NameValueCollection nameValueCollection = WmDataTools.getNameValueCollectionFromDataRow(dataRow); string nameValueString = WmDataTools.getQueryStringFromNameValueCollection(nameValueCollection); createTransactionObject(tableName, rowId, dataRowAction, referenceTransactionMomentUtcTicks, nameValueString); // Step 4: Restore the culture setting if (didChangeCulture) { Thread.CurrentThread.CurrentCulture = originalCultureInfo; } } } public void registerInsertOrUpdateTransaction(WmIntermediateObject intermediateObject, int rowId, WmDataRowAction dataRowAction, object objectInstance, long referenceTransactionMomentUtcTicks) { if (!intermediateObject.TableName.Equals("wmdatatransaction")) { // Step 1: Set culture to us english to make sure date time and numbers are always formatted correctly bool didChangeCulture = false; CultureInfo originalCultureInfo = Thread.CurrentThread.CurrentCulture; if (!Thread.CurrentThread.CurrentCulture.Name.Equals("en-US")) { Thread.CurrentThread.CurrentCulture = cultureInfoUs; } // Step 2: Create the Transaction object NameValueCollection nameValueCollection = WmDataTools.getNameValueCollectionFromObjectInstance(intermediateObject, objectInstance); string nameValueString = WmDataTools.getQueryStringFromNameValueCollection(nameValueCollection); createTransactionObject(intermediateObject.TableName, rowId, dataRowAction, referenceTransactionMomentUtcTicks, nameValueString); // Step 4: Restore the culture setting if (didChangeCulture) { Thread.CurrentThread.CurrentCulture = originalCultureInfo; } } } public void registerChecksumTransaction(string tableName) { createTransactionObject(tableName, -1, WmDataRowAction.CHECKSUM, -1, null); } protected void createTransactionObject(string tableName, int objectId, WmDataRowAction dataRowAction, long referenceTransactionMomentUtcTicks, string nameValueString) { WmDataTransaction transaction = new WmDataTransaction(); transaction.DataRowAction = dataRowAction; transaction.LocalMomentUtcTicks = DateTime.UtcNow.Ticks; transaction.RemoteMomentUtcTicks = referenceTransactionMomentUtcTicks; transaction.ObjectId = objectId; transaction.TableName = tableName; transaction.NameValueQueryString = nameValueString; transaction.TableChecksumAfterThisTransaction = data.getChecksum(tableName); // Step 3: Save the transaction object data.addObject(transaction); } public void importTransaction(WmDataTransaction transaction) { // Set culture to us english to make sure date time and numbers are always formatted correctly bool didChangeCulture = false; CultureInfo originalCultureInfo = Thread.CurrentThread.CurrentCulture; if (!Thread.CurrentThread.CurrentCulture.Name.Equals("en-US")) { Thread.CurrentThread.CurrentCulture = cultureInfoUs; } switch (transaction.DataRowAction) { case WmDataRowAction.ADD: importTransactionAdd(transaction); break; case WmDataRowAction.UPDATE: importTransactionUpdate(transaction); break; case WmDataRowAction.DELETE: importTransactionDelete(transaction); break; } // Restore the culture setting if (didChangeCulture) { Thread.CurrentThread.CurrentCulture = originalCultureInfo; } } protected void importTransactionAdd(WmDataTransaction transaction) { WmIntermediateObject intermediateObject = intermediateObjectManager.getExistingIntermediateObjectByTableName(transaction.TableName); if (intermediateObject == null) { throw new NullReferenceException("WmDataTransactionManager: Attempt to import object that is unknown at the Intermediate Object Manager, try to issue a local get select call first"); } // create an object instance with the given properties object objectInstance = intermediateObject.Creator.Invoke(); NameValueCollection nameValueCollection = transaction.getNameValueCollection(); foreach (WmIntermediateObjectProperty objectProperty in intermediateObject.Properties) { objectProperty.Setter(objectInstance, objectProperty.parseValueFromString(nameValueCollection[objectProperty.DataName])); } data.addObject(objectInstance, true, transaction.LocalMomentUtcTicks); } protected void importTransactionUpdate(WmDataTransaction transaction) { WmIntermediateObject intermediateObject = intermediateObjectManager.getExistingIntermediateObjectByTableName(transaction.TableName); if (intermediateObject == null) { throw new NullReferenceException("WmDataTransactionManager: Attempt to update object that is unknown at the Intermediate Object Manager, try to issue a local get select call first"); } object objectInstance = null; objectInstance = data.getObject(intermediateObject.ObjectType, transaction.ObjectId); if (objectInstance != null) { NameValueCollection nameValueCollection = transaction.getNameValueCollection(); foreach (WmIntermediateObjectProperty objectProperty in intermediateObject.Properties) { objectProperty.Setter(objectInstance, objectProperty.parseValueFromString(nameValueCollection[objectProperty.DataName])); } data.updateObject(objectInstance, transaction.LocalMomentUtcTicks); } } protected void importTransactionDelete(WmDataTransaction transaction) { WmIntermediateObject intermediateObject = intermediateObjectManager.getExistingIntermediateObjectByTableName(transaction.TableName); if (intermediateObject == null) { throw new NullReferenceException("WmDataTransactionManager: Attempt to delete object that is unknown at the Intermediate Object Manager, try to issue a local get select call first"); } Type objectType = intermediateObject.ObjectType; data.deleteObject(objectType, transaction.ObjectId, transaction.LocalMomentUtcTicks); } } }