/// <summary> /// Sends a deleteItem method to the clients that are sync'd to sequences that contain this item. /// It does not send a delete message to the adapter/assembler but instead assumes that this /// item is already have been deleted from the database or is being deleted in this transaction. /// If you rollback the transaction, this message is also rolled back. /// /// This version of the delete method causes clients to generate a conflict if they have a version /// of the item that does not match the version of the item specified. You can use the /// DeleteItemWithId method to unconditionally delete an item on the client if you do not have /// the original version. /// </summary> /// <param name="destination">Name of the destination containing the item to be deleted.</param> /// <param name="item">Version of the item to delete. Clients can detect a conflict if this version of the item does not match the version they are currently managing.</param> public void DeleteItem(string destination, object item) { DataMessage dataMessage = new DataMessage(); DataDestination dataDestination = _dataService.GetDestination(destination) as DataDestination; dataMessage.operation = DataMessage.DeleteOperation; dataMessage.body = item; dataMessage.destination = destination; if (_clientId != null) { dataMessage.clientId = _clientId; } else { dataMessage.clientId = "srv:" + Guid.NewGuid().ToString("D"); } dataMessage.identity = Identity.GetIdentity(item, dataDestination); dataMessage.messageId = "srv:" + Guid.NewGuid().ToString("D") + ":" + _idCounter.ToString(); System.Threading.Interlocked.Increment(ref _idCounter); ArrayList messages = new ArrayList(1); messages.Add(dataMessage); MessageBatch messageBatch = new MessageBatch(dataMessage, messages); AddProcessedMessageBatch(messageBatch); }
/// <summary> /// Send an update event to clients subscribed to this message. Note that this method does not send /// the change to the adapter/assembler - it assumes that the changes have already been applied /// or are being applied. It only updates the clients with the new version of this data. /// /// You must supply a destination parameter and a new version of the object. If you supply a /// non-null previous version, this object is used to detect conflicts on the client in case /// the client's version of the data does not match the previous version. You may also supply /// a list of property names that have changed as a hint to the client to indicate which properties /// should be checked for conflicts and updated. If you supply null for the changes, all /// properties on the client are updated. These property names do not accept any kind of dot /// notation to specify that a property of a property has changed. Only top level property /// names are allowed. /// </summary> /// <param name="destination">Name of the Data Management Services destination that is managing the item you want to update.</param> /// <param name="newVersion">New version of the item to update. The identity of the item is used to determine which item to update.</param> /// <param name="previousVersion">If not null, this contains a version of the item you intend to update. The client can detect a conflict if its version does not match the previousVersion. If you specify the value as null, a conflict is only detected if the client has pending changes for the item being updated.</param> /// <param name="changes">Array of property names which are to be updated. You can provide a null value to indicate that all property values may have changed.</param> public void UpdateItem(string destination, object newVersion, object previousVersion, string[] changes) { DataMessage dataMessage = new DataMessage(); DataDestination dataDestination = _dataService.GetDestination(destination) as DataDestination; object[] body = new object[3]; body[0] = changes; body[2] = newVersion; body[1] = previousVersion; dataMessage.operation = DataMessage.UpdateOperation; dataMessage.body = body; dataMessage.destination = destination; if (_clientId != null) { dataMessage.clientId = _clientId; } else { dataMessage.clientId = "srv:" + Guid.NewGuid().ToString("D"); } dataMessage.identity = Identity.GetIdentity(newVersion, dataDestination); dataMessage.messageId = "srv:" + Guid.NewGuid().ToString("D") + ":" + _idCounter.ToString(); System.Threading.Interlocked.Increment(ref _idCounter); ArrayList messages = new ArrayList(1); messages.Add(dataMessage); MessageBatch messageBatch = new MessageBatch(dataMessage, messages); _processedMessageBatches.Add(messageBatch); }
void SyncSequenceChanges(DataMessage dataMessage, DataServiceTransaction dataServiceTransaction) { lock (_objLock) { ArrayList sequenceList = new ArrayList(_sequenceIdToSequenceHash.Values.Count); sequenceList.AddRange(_sequenceIdToSequenceHash.Values); //Hashtable may be changed here foreach (Sequence sequence in sequenceList) { switch (dataMessage.operation) { case DataMessage.CreateOperation: case DataMessage.CreateAndSequenceOperation: RefreshSequence(sequence, dataMessage, dataMessage.body, dataServiceTransaction); break; case DataMessage.DeleteOperation: { //RefreshSequence(sequence, dataMessage, dataMessage.body, dataServiceTransaction); Identity identity = Identity.GetIdentity(dataMessage.body, _dataDestination); int index = sequence.IndexOf(identity); if (index != -1) { RemoveIdentityFromSequence(sequence, identity, dataServiceTransaction); } } break; case DataMessage.UpdateOperation: RefreshSequence(sequence, dataMessage, (dataMessage.body as IList)[2], dataServiceTransaction); break; } } } }
public Sequence RefreshSequence(Sequence sequence, DataMessage dataMessage, object item, DataServiceTransaction dataServiceTransaction) { if (sequence.Parameters == null) { return(sequence); } DotNetAdapter dotNetAdapter = _dataDestination.ServiceAdapter as DotNetAdapter; if (dotNetAdapter != null) { bool isCreate = (dataMessage.operation == DataMessage.CreateOperation || dataMessage.operation == DataMessage.CreateAndSequenceOperation); int fill = dotNetAdapter.RefreshFill(sequence.Parameters, item, isCreate); switch (fill) { case Assembler.ExecuteFill: { IList parameters = sequence.Parameters; //if (parameters == null) // parameters = new object[0]; DataMessage fillDataMessage = new DataMessage(); fillDataMessage.clientId = dataMessage.clientId; fillDataMessage.operation = DataMessage.FillOperation; fillDataMessage.body = parameters != null ? parameters : new object[0]; IList result = _dataDestination.ServiceAdapter.Invoke(fillDataMessage) as IList; return(CreateSequence(dataMessage.clientId as string, result, parameters, dataServiceTransaction)); } case Assembler.AppendToFill: { Identity identity = Identity.GetIdentity(item, _dataDestination); if (!sequence.Contains(identity)) { AddIdentityToSequence(sequence, identity, dataServiceTransaction); } _itemIdToItemHash[identity] = new ItemWrapper(item); } break; case Assembler.RemoveFromFill: { Identity identity = Identity.GetIdentity(item, _dataDestination); if (sequence.Contains(identity)) { RemoveIdentityFromSequence(sequence, identity, dataServiceTransaction); } } break; case Assembler.DoNotExecuteFill: break; } } return(sequence); }
public Sequence CreateSequence(string clientId, IList result, IList parameters, DataServiceTransaction dataServiceTransaction) { Sequence sequence = null; Identity[] identities = new Identity[result.Count]; lock (_objLock) { for (int i = 0; i < identities.Length; i++) { if (result[i] != null) { Identity identity = Identity.GetIdentity(result[i], _dataDestination); identities[i] = identity; if (!_itemIdToItemHash.ContainsKey(identity)) { _itemIdToItemHash.Add(identity, new ItemWrapper(result[i])); } else { ItemWrapper itemWrapper = _itemIdToItemHash[identity] as ItemWrapper; itemWrapper.Instance = result[i]; } } } //Lookup existing sequence if (parameters != null) { if (_parametersToSequenceIdHash.Contains(parameters)) { sequence = _parametersToSequenceIdHash[parameters] as Sequence; } } else { IDictionary sequenceIdMap = _itemIdToSequenceIdMapHash[identities[0]] as IDictionary; if (sequenceIdMap != null) { foreach (Sequence sequenceTmp in sequenceIdMap.Values) { if (sequenceTmp.Parameters == null) { sequence = sequenceTmp; break; } } } } //if (parameters == null) // parameters = new ArrayList(); if (sequence == null) { sequence = new Sequence(); sequence.Id = sequence.GetHashCode(); object[] parametersArray = null; if (parameters != null) { parametersArray = new object[parameters.Count]; parameters.CopyTo(parametersArray, 0); sequence.Parameters = parametersArray; _parametersToSequenceIdHash[parameters] = sequence; } for (int i = 0; i < identities.Length; i++) { Identity identity = identities[i]; AddIdentityToSequence(sequence, identity, dataServiceTransaction); } _sequenceIdToSequenceHash[sequence.Id] = sequence; if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.SequenceManager_CreateSeq, sequence.Id, clientId)); } } else { for (int i = 0; i < identities.Length; i++) { Identity identity = identities[i]; Identity existingIdentity = null; if (i < sequence.Count) { existingIdentity = sequence[i]; } if (!identity.Equals(existingIdentity)) { //Identity not found in sequence if (!sequence.Contains(identity)) { int position = AddIdentityToSequence(sequence, identity, dataServiceTransaction); } } } } sequence.AddSubscriber(clientId); ArrayList sequences; if (_clientIdToSequenceHash.Contains(clientId)) { sequences = _clientIdToSequenceHash[clientId] as ArrayList; } else { sequences = new ArrayList(); _clientIdToSequenceHash[clientId] = sequences; } if (!sequences.Contains(sequence)) { sequences.Add(sequence); } } return(sequence); }