/// <summary> /// Initializes a new instance of the <see cref="EvaluateReactionRegistrationResult"/> class. /// </summary> /// <param name="reactionEvent">The reaction.</param> /// <param name="recordSetHandlingMementos">The mementos for completing or canceling.</param> public EvaluateReactionRegistrationResult( ReactionEvent reactionEvent, IReadOnlyCollection <RecordSetHandlingMemento> recordSetHandlingMementos) { if (reactionEvent != null) { recordSetHandlingMementos.MustForArg(nameof(recordSetHandlingMementos)).NotBeNullNorEmptyEnumerableNorContainAnyNulls(); } else { recordSetHandlingMementos.MustForArg(nameof(recordSetHandlingMementos)).NotBeNull(); } this.ReactionEvent = reactionEvent; this.RecordSetHandlingMementos = recordSetHandlingMementos; }
public override EvaluateReactionRegistrationResult Execute( EvaluateReactionRegistrationOp operation) { if (operation.ReactionRegistration.Dependencies.Count != 1) { throw new NotSupportedException(Invariant($"Only 1 single {typeof(RecordFilterReactorDependency)} is supported, {operation.ReactionRegistration.Dependencies.Count} were supplied.")); } var dependency = operation.ReactionRegistration.Dependencies.Single(); var recordFilterDependency = dependency as RecordFilterReactorDependency; if (recordFilterDependency == null) { throw new NotSupportedException(Invariant($"Only {typeof(RecordFilterReactorDependency)} is supported, {dependency?.GetType().ToStringReadable()}.")); } var reactionId = Invariant($"{operation.ReactionRegistration.Id}___{DateTime.UtcNow.ToStringInvariantPreferred()}"); var streamRepToHandledDependencyRecordIdToBeIncludedMap = new Dictionary <IStreamRepresentation, HashSet <long> >(); var handledRecordMementos = new List <RecordSetHandlingMemento>(); var allRequiredSeen = true; foreach (var recordFilterEntry in recordFilterDependency.Entries) { try { var stream = this.streamFactory.Execute(new GetStreamFromRepresentationOp(recordFilterEntry.StreamRepresentation)); stream.MustForOp(nameof(stream)).BeAssignableToType <ISyncReturningProtocol <StandardTryHandleRecordOp, TryHandleRecordResult> >(); var streamProtocol = (ISyncReturningProtocol <StandardTryHandleRecordOp, TryHandleRecordResult>)stream; var tryHandleConcern = EvaluateReactionRegistrationOp.BuildHandlingConcern(operation.ReactionRegistration, recordFilterEntry); var handledIds = new HashSet <long>(); // this is because we could get duplicates... StreamRecord currentRecord = null; do { var tryHandleRecordOp = new StandardTryHandleRecordOp( tryHandleConcern, recordFilterEntry.RecordFilter, streamRecordItemsToInclude: StreamRecordItemsToInclude.MetadataOnly, tags: new[] { new NamedValue <string>(TagNames.PotentialReactionId, reactionId), }); var tryHandleRecordResult = streamProtocol.Execute(tryHandleRecordOp); currentRecord = tryHandleRecordResult?.RecordToHandle; if (currentRecord != null) { handledIds.Add(currentRecord.InternalRecordId); } }while (currentRecord != null); if (handledIds.Any()) { var streamProtocolFactoryForActions = (IStreamRecordHandlingProtocolFactory)stream; var streamHandlingProtocolForActions = streamProtocolFactoryForActions.GetStreamRecordHandlingProtocols(); void CompleteAction() { foreach (var handledInternalRecordId in handledIds) { var completeHandlingOp = new CompleteRunningHandleRecordOp( handledInternalRecordId, tryHandleConcern); streamHandlingProtocolForActions.Execute( completeHandlingOp); } } void CancelAction() { foreach (var handledInternalRecordId in handledIds) { var cancelHandlingOp = new CancelRunningHandleRecordOp( handledInternalRecordId, tryHandleConcern, "Not all required dependencies present."); streamHandlingProtocolForActions.Execute( cancelHandlingOp); } } var actionableSetForTracking = new RecordSetHandlingMemento(CompleteAction, CancelAction); handledRecordMementos.Add(actionableSetForTracking); if (recordFilterEntry.IncludeInReaction) { if (streamRepToHandledDependencyRecordIdToBeIncludedMap.ContainsKey(recordFilterEntry.StreamRepresentation)) { streamRepToHandledDependencyRecordIdToBeIncludedMap[recordFilterEntry.StreamRepresentation].AddRange(handledIds); } else { streamRepToHandledDependencyRecordIdToBeIncludedMap.Add(recordFilterEntry.StreamRepresentation, handledIds); } } } else { if (recordFilterEntry.RequiredForReaction && !operation.OverrideRequired) { allRequiredSeen = false; break; } } } catch (Exception ex) { throw new ReactorException(Invariant($"Failed to process entry: {recordFilterEntry}."), ex, operation); } } EvaluateReactionRegistrationResult result; if (!allRequiredSeen) { foreach (var recordSetHandlingMemento in handledRecordMementos) { recordSetHandlingMemento.CancelSet(); } // no reaction created since not all requirement met. result = new EvaluateReactionRegistrationResult(null, new List <RecordSetHandlingMemento>()); } else if (!handledRecordMementos.Any()) { // no reaction created since there wasn't anything to react to. result = new EvaluateReactionRegistrationResult(null, new List <RecordSetHandlingMemento>()); } else { var streamRepresentationToInternalRecordIdsMap = streamRepToHandledDependencyRecordIdToBeIncludedMap.ToDictionary( k => k.Key, v => (IReadOnlyList <long>)v.Value.ToList()); var reactionTags = (operation.ReactionRegistration.Tags ?? new List <NamedValue <string> >()) .Union( new[] { new NamedValue <string>( TagNames.ReactionRegistrationId, operation.ReactionRegistration.Id), }) .ToList(); var reactionEvent = new ReactionEvent( reactionId, operation.ReactionRegistration.Id, operation.ReactionRegistration.ReactionContext, streamRepresentationToInternalRecordIdsMap, DateTime.UtcNow, reactionTags); result = new EvaluateReactionRegistrationResult(reactionEvent, handledRecordMementos); } return(result); }