/// <summary> /// Reset the negotiation to a "in negotiation" state. /// </summary> /// <param name="consumerTrustNegotiations">The the negotiations to reset.</param> internal static void Reject(ConsumerTrustNegotiationInfo[] consumerTrustNegotiations) { // An instance of the shared data model is required to use its methods. DataModel dataModel = new DataModel(); // The business logic requires the current time and the user identifier for auditing. Guid createUserId = TradingSupport.UserId; DateTime createDateTime = DateTime.UtcNow; DateTime modifiedTime = createDateTime; Guid modifiedUserId = createUserId; // This Web Method comes with an implicit transaction that is linked to its execution. DataModelTransaction dataModelTransaction = DataModelTransaction.Current; // This method can handle a batch of updates in a single transaction. foreach (ConsumerTrustNegotiationInfo consumerTrustNegotiationInfo in consumerTrustNegotiations) { List <ConsumerTrustNegotiationPaymentMethodTypeInfo> counterItems = new List <ConsumerTrustNegotiationPaymentMethodTypeInfo>(); // The blotter is not passed in from the client but is used Guid blotterId = Guid.Empty; Status negotiationStatus; TrustNegotiationInfo trustNegotiationInfo = null; // This is the next negotiation in the batch to be updated. ConsumerTrustNegotiationRow consumerTrustNegotiationRow = DataModel.ConsumerTrustNegotiation.ConsumerTrustNegotiationKey.Find(consumerTrustNegotiationInfo.ConsumerTrustNegotiationId); try { // Lock the current negotation record for reading. The data model doesn't support reader lock promotion, so the programming model is to // lock the database, collect the data, release the locks and then write. This model is especially important when iterating through a // large batch to prevent the number of locks from growing to large. consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); // The blotter identifier is used for access control and is not passed in by the client. blotterId = consumerTrustNegotiationRow.BlotterId; negotiationStatus = StatusMap.FromId(consumerTrustNegotiationRow.StatusId); trustNegotiationInfo = new TrustNegotiationInfo(consumerTrustNegotiationRow); // Determine whether the client has the right to modify this record. if (!TradingSupport.HasAccess(dataModelTransaction, blotterId, AccessRight.Write)) { throw new FaultException <FluidTrade.Core.SecurityFault>(new SecurityFault("You do not have write access to the selected object.")); } // The payment methods are maintained as a vector associated with the negotiation record. This will lock each of the records and read the // payment methods into a data structure so the locks don't need to be held when it is time to write foreach (var consumerTrustNegotiationOfferPaymentMethodRow in consumerTrustNegotiationRow.GetConsumerTrustNegotiationCounterPaymentMethodRows()) { try { // Temporarily lock the record containing the payment method. consumerTrustNegotiationOfferPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); // This list is used to delete the payment methods that are no longer part of this negotiation. counterItems.Add( new ConsumerTrustNegotiationPaymentMethodTypeInfo( consumerTrustNegotiationOfferPaymentMethodRow.PaymentMethodTypeId, consumerTrustNegotiationOfferPaymentMethodRow.ConsumerTrustNegotiationCounterPaymentMethodId, consumerTrustNegotiationOfferPaymentMethodRow.RowVersion)); } finally { // At this point the payment method isn't needed. consumerTrustNegotiationOfferPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } } MatchRow matchRow = DataModel.Match.MatchKey.Find(trustNegotiationInfo.MatchId); try { matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); trustNegotiationInfo.MatchRowVersion = matchRow.RowVersion; trustNegotiationInfo.ContraMatchId = matchRow.ContraMatchId; } finally { matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } MatchRow contraMatchRow = DataModel.Match.MatchKey.Find(trustNegotiationInfo.ContraMatchId); try { contraMatchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); trustNegotiationInfo.ContraMatchRowVersion = contraMatchRow.RowVersion; } finally { contraMatchRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } } finally { // At this point, the negotiation record isn't needed. It is critical to release the reader locks before attempting a write. consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // At this point, all the data for this operation has been collected and the CRUD operations can be invoked to finish the update. Note that // the counter party information is not modified here, but is done through the Chinese wall. Guid newNegotiationId = Guid.NewGuid(); dataModel.CreateConsumerTrustNegotiation( trustNegotiationInfo.AccountBalance, trustNegotiationInfo.BlotterId, newNegotiationId, trustNegotiationInfo.CounterPaymentLength, trustNegotiationInfo.CounterPaymentStartDateLength, trustNegotiationInfo.CounterPaymentStartDateUnitId, trustNegotiationInfo.CounterSettlementUnitId, trustNegotiationInfo.CounterSettlementValue, createDateTime, createUserId, trustNegotiationInfo.CreditCardId, trustNegotiationInfo.IsRead, trustNegotiationInfo.IsReply, trustNegotiationInfo.MatchId, modifiedTime, modifiedUserId, consumerTrustNegotiationInfo.PaymentLength, consumerTrustNegotiationInfo.PaymentStartDateLength, consumerTrustNegotiationInfo.PaymentStartDateUnitId, consumerTrustNegotiationInfo.SettlementUnitId, consumerTrustNegotiationInfo.SettlementValue, StatusMap.FromCode(Status.Rejected), out trustNegotiationInfo.Version); // This will add the payment methods to the negotiation that are not already there. foreach (Guid paymentMethodTypeId in consumerTrustNegotiationInfo.PaymentMethodTypes) { dataModel.CreateConsumerTrustNegotiationOfferPaymentMethod( blotterId, newNegotiationId, Guid.NewGuid(), paymentMethodTypeId); } foreach (ConsumerTrustNegotiationPaymentMethodTypeInfo consumerTrustNegotiationPaymentMethodTypeInfo in counterItems) { dataModel.UpdateConsumerTrustNegotiationCounterPaymentMethod( blotterId, null, new Object[] { consumerTrustNegotiationPaymentMethodTypeInfo.ConsumerTrustNegotiationOfferPaymentMethodId }, newNegotiationId, consumerTrustNegotiationPaymentMethodTypeInfo.PaymentMethodInfoId, consumerTrustNegotiationPaymentMethodTypeInfo.RowVersion); } //Reset the Match Status Id. This is required so the match engine will redo the match. The //match engine does not recalculate if it is not in the initial three stages of - Valid, Partial, ValidwithFunds dataModel.UpdateMatch( null, null, null, null, null, null, null, new object[] { trustNegotiationInfo.MatchId }, trustNegotiationInfo.MatchRowVersion, StatusMap.FromCode(Status.ValidMatch), null); //Reset the Contra Match Status Id dataModel.UpdateMatch( null, null, null, null, null, null, null, new object[] { trustNegotiationInfo.ContraMatchId }, trustNegotiationInfo.ContraMatchRowVersion, StatusMap.FromCode(Status.ValidMatch), null); } }
/// <summary> /// Update a Consumer Trust Negotiation Record. /// </summary> internal static void Update(ConsumerTrustNegotiationInfo[] consumerTrustNegotiations) { // An instance of the shared data model is required to use its methods. DataModel dataModel = new DataModel(); // The business logic requires the current time and the user identifier for auditing. Guid createUserId = TradingSupport.UserId; DateTime createDateTime = DateTime.UtcNow; DateTime modifiedTime = createDateTime; Guid modifiedUserId = createUserId; // This Web Method comes with an implicit transaction that is linked to its execution. DataModelTransaction dataModelTransaction = DataModelTransaction.Current; // This method can handle a batch of updates in a single transaction. foreach (ConsumerTrustNegotiationInfo consumerTrustNegotiationInfo in consumerTrustNegotiations) { // The payment methods available to this negotiation is a vector. Rather than delete everything and re-add it anytime an update is made, a // list of changes is constructed: new payment methods are added, obsolete payment methods are deleted and the ones that haven't changed are // left alone. These list help to work out the differences. List <ConsumerTrustNegotiationPaymentMethodTypeInfo> counterItems = new List <ConsumerTrustNegotiationPaymentMethodTypeInfo>(); // The blotter is not passed in from the client but is used Guid blotterId = Guid.Empty; TrustNegotiationInfo trustNegotiationInfo = null; // This is the next negotiation in the batch to be updated. ConsumerTrustNegotiationRow consumerTrustNegotiationRow = DataModel.ConsumerTrustNegotiation.ConsumerTrustNegotiationKey.Find(consumerTrustNegotiationInfo.ConsumerTrustNegotiationId); Guid matchId = Guid.Empty; Int64 originalVersion = Int64.MinValue; // Lock the current negotation record for reading. The data model doesn't support reader lock promotion, so the programming model is to // lock the database, collect the data, release the locks and then write. This model is especially important when iterating through a // large batch to prevent the number of locks from growing to large. consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { matchId = consumerTrustNegotiationRow.MatchId; originalVersion = consumerTrustNegotiationRow.Version; } finally { consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId); consumerTrustNegotiationRow = null; } //Determine the most recent Negotiation to grab the counter payment methods. Int64 maxVersion = Int64.MinValue; MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId); matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { foreach (ConsumerTrustNegotiationRow versionRow in matchRow.GetConsumerTrustNegotiationRows()) { try { versionRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); if (versionRow.Version > maxVersion) { maxVersion = versionRow.Version; consumerTrustNegotiationRow = versionRow; } } finally { versionRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } } } finally { matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { //Check for rowversion if (originalVersion != consumerTrustNegotiationRow.Version) { throw new global::System.ServiceModel.FaultException <FluidTrade.Core.OptimisticConcurrencyFault>( new global::FluidTrade.Core.OptimisticConcurrencyFault("ConsumerTrustNegotiation", new object[] { consumerTrustNegotiationInfo.ConsumerTrustNegotiationId }), new FaultReason("Negotiation is busy. Please try again!")); } // The blotter identifier is used for access control and is not passed in by the client. blotterId = consumerTrustNegotiationRow.BlotterId; trustNegotiationInfo = new TrustNegotiationInfo(consumerTrustNegotiationRow); // Determine whether the client has the right to modify this record. if (!TradingSupport.HasAccess(dataModelTransaction, blotterId, AccessRight.Write)) { throw new FaultException <FluidTrade.Core.SecurityFault>(new SecurityFault("You do not have write access to the selected object.")); } // The payment methods are maintained as a vector associated with the negotiation record. This will lock each of the records and read the // payment methods into a data structure so the locks don't need to be held when it is time to write foreach (var consumerTrustNegotiationOfferPaymentMethodRow in consumerTrustNegotiationRow.GetConsumerTrustNegotiationCounterPaymentMethodRows()) { try { // Temporarily lock the record containing the payment method. consumerTrustNegotiationOfferPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); // This list is used to delete the payment methods that are no longer part of this negotiation. counterItems.Add( new ConsumerTrustNegotiationPaymentMethodTypeInfo( consumerTrustNegotiationOfferPaymentMethodRow.PaymentMethodTypeId, consumerTrustNegotiationOfferPaymentMethodRow.ConsumerTrustNegotiationCounterPaymentMethodId, consumerTrustNegotiationOfferPaymentMethodRow.RowVersion)); } finally { // At this point the payment method isn't needed. consumerTrustNegotiationOfferPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } } } finally { // At this point, the negotiation record isn't needed. It is critical to release the reader locks before attempting a write. consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // At this point, all the data for this operation has been collected and the CRUD operations can be invoked to finish the update. Note that // the counter party information is not modified here, but is done through the Chinese wall. Guid newNegotiationId = Guid.NewGuid(); dataModel.CreateConsumerTrustNegotiation( trustNegotiationInfo.AccountBalance, trustNegotiationInfo.BlotterId, newNegotiationId, trustNegotiationInfo.CounterPaymentLength, trustNegotiationInfo.CounterPaymentStartDateLength, trustNegotiationInfo.CounterPaymentStartDateUnitId, trustNegotiationInfo.CounterSettlementUnitId, trustNegotiationInfo.CounterSettlementValue, createDateTime, createUserId, trustNegotiationInfo.CreditCardId, trustNegotiationInfo.IsRead, trustNegotiationInfo.IsReply, trustNegotiationInfo.MatchId, modifiedTime, modifiedUserId, consumerTrustNegotiationInfo.PaymentLength, consumerTrustNegotiationInfo.PaymentStartDateLength, consumerTrustNegotiationInfo.PaymentStartDateUnitId, consumerTrustNegotiationInfo.SettlementUnitId, consumerTrustNegotiationInfo.SettlementValue, consumerTrustNegotiationInfo.StatusId, out trustNegotiationInfo.Version); // This will add the payment methods to the negotiation that are not already there. foreach (Guid paymentMethodTypeId in consumerTrustNegotiationInfo.PaymentMethodTypes) { dataModel.CreateConsumerTrustNegotiationOfferPaymentMethod( blotterId, newNegotiationId, Guid.NewGuid(), paymentMethodTypeId); } //Since we cannot create new counter payments, we will update the existing ones. foreach (ConsumerTrustNegotiationPaymentMethodTypeInfo consumerTrustNegotiationPaymentMethodTypeInfo in counterItems) { dataModel.UpdateConsumerTrustNegotiationCounterPaymentMethod( blotterId, null, new Object[] { consumerTrustNegotiationPaymentMethodTypeInfo.ConsumerTrustNegotiationOfferPaymentMethodId }, newNegotiationId, consumerTrustNegotiationPaymentMethodTypeInfo.PaymentMethodInfoId, consumerTrustNegotiationPaymentMethodTypeInfo.RowVersion); } } }