/// <summary> /// Downloads the exception body. /// </summary> /// <param name="direction">The direction.</param> /// <param name="id"></param> /// <returns>The exception</returns> /// <exception cref="ArgumentNullException">messageId - messageId parameter cannot be null</exception> public async Task <Stream> DownloadExceptionMessageBody(Direction direction, long id) { if (id <= 0) { throw new ArgumentOutOfRangeException(nameof(id), @"Invalid value for id"); } if (!Enum.IsDefined(typeof(Direction), direction)) { throw new InvalidEnumArgumentException(nameof(direction), (int)direction, typeof(Direction)); } string body; if (direction == Direction.Inbound) { body = await context .InExceptions .Where(msg => msg.Id == id) .Select(msg => msg.MessageLocation) .FirstOrDefaultAsync(); } else { body = await context .OutExceptions .Where(msg => msg.Id == id) .Select(msg => msg.MessageLocation) .FirstOrDefaultAsync(); } return(await bodyStore.LoadMessageBodyAsync(body)); }
/// <summary> /// Execute the step for a given <paramref name="messagingContext"/>. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { var entityMessage = messagingContext?.ReceivedMessage as ReceivedEntityMessage; if (!(entityMessage?.Entity is InMessage receivedInMessage)) { throw new InvalidOperationException( "The MessagingContext must contain a ReceivedMessage that represents an InMessage." + Environment.NewLine + "Other types of ReceivedMessage models are not supported in this Step."); } // Forward message by creating an OutMessage and set operation to 'ToBeProcessed'. Logger.Info($"{messagingContext.LogTag} Create a message that will be forwarded to the next MSH"); using (Stream originalInMessage = await _messageStore.LoadMessageBodyAsync(receivedInMessage.MessageLocation)) { string outLocation = await _messageStore.SaveAS4MessageStreamAsync( _configuration.OutMessageStoreLocation, originalInMessage); originalInMessage.Position = 0; AS4Message msg = await SerializerProvider.Default .Get(receivedInMessage.ContentType) .DeserializeAsync(originalInMessage, receivedInMessage.ContentType); using (DatastoreContext dbContext = _createDataStoreContext()) { var repository = new DatastoreRepository(dbContext); // Only create an OutMessage for the primary message-unit. OutMessage outMessage = OutMessageBuilder .ForMessageUnit( msg.PrimaryMessageUnit, receivedInMessage.ContentType, messagingContext.SendingPMode) .BuildForForwarding(outLocation, receivedInMessage); Logger.Debug("Insert OutMessage {{Intermediary=true, Operation=ToBeProcesed}}"); repository.InsertOutMessage(outMessage); // Set the InMessage to Forwarded. // We do this for all InMessages that are present in this AS4 Message repository.UpdateInMessages( m => msg.MessageIds.Contains(m.EbmsMessageId), r => r.Operation = Operation.Forwarded); await dbContext.SaveChangesAsync(); } } return(StepResult.Success(messagingContext)); }
private async Task <Stream> TryLoadMessageBody(IAS4MessageBodyStore store) { try { return(await store.LoadMessageBodyAsync(MessageLocation)); } catch (Exception exception) { LogManager.GetCurrentClassLogger().Error(exception.Message); return(null); } }
/// <summary> /// Gets the non-intermediary stored <see cref="AS4Message"/>s matching the specified ebMS <paramref name="messageIds"/>. /// </summary> /// <param name="messageIds">The ebMS message identifiers.</param> /// <returns></returns> public async Task <IEnumerable <AS4Message> > GetNonIntermediaryAS4UserMessagesForIds(IEnumerable <string> messageIds) { if (messageIds == null) { throw new ArgumentNullException(nameof(messageIds)); } if (!messageIds.Any()) { Logger.Trace("Specified ebMS message identifiers is empty"); return(Enumerable.Empty <AS4Message>()); } IEnumerable <OutMessage> messages = _repository.GetOutMessageData( m => messageIds.Contains(m.EbmsMessageId) && m.Intermediary == false, m => m) .Where(m => m != null); if (!messages.Any()) { return(Enumerable.Empty <AS4Message>()); } var foundMessages = new Collection <AS4Message>(); foreach (OutMessage m in messages) { Stream body = await _messageBodyStore.LoadMessageBodyAsync(m.MessageLocation); AS4Message foundMessage = await SerializerProvider.Default .Get(m.ContentType) .DeserializeAsync(body, m.ContentType); foundMessages.Add(foundMessage); } return(foundMessages.AsEnumerable()); }
/// <summary> /// Selects the available <see cref="SignalMessage"/>s that are ready to be bundled (PiggyBacked) with the given <see cref="PullRequest"/>. /// </summary> /// <param name="pr">The <see cref="PullRequest"/> for which a selection of <see cref="SignalMessage"/>s are returned.</param> /// <param name="sendingPMode">The sending configuration used to select <see cref="SignalMessage"/>s with the same configuration.</param> /// <param name="bodyStore">The body store at which the <see cref="SignalMessage"/>s are persisted.</param> /// <returns> /// An subsection of the <see cref="SignalMessage"/>s where the referenced send <see cref="UserMessage"/> matches the given <paramref name="pr"/> /// and where the sending configuration given in the <paramref name="sendingPMode"/> matches the stored <see cref="SignalMessage"/> sending configuration. /// </returns> internal async Task <IEnumerable <SignalMessage> > SelectToBePiggyBackedSignalMessagesAsync( PullRequest pr, SendingProcessingMode sendingPMode, IAS4MessageBodyStore bodyStore) { if (pr == null) { throw new ArgumentNullException(nameof(pr)); } if (sendingPMode == null) { throw new ArgumentNullException(nameof(sendingPMode)); } if (bodyStore == null) { throw new ArgumentNullException(nameof(bodyStore)); } string url = sendingPMode.PushConfiguration?.Protocol?.Url; if (String.IsNullOrWhiteSpace(url)) { throw new ArgumentException( @"SendingPMode.PushConfiguration.Protocol.Url cannot be blank", nameof(sendingPMode.PushConfiguration.Protocol.Url)); } bool pullRequestSigned = sendingPMode.Security?.Signing?.IsEnabled == true; return(await _context.TransactionalAsync(async db => { IEnumerable <OutMessage> query = db.NativeCommands .SelectToBePiggyBackedSignalMessages(url, pr.Mpc); var toBePiggyBackedSignals = new Collection <MessageUnit>(); foreach (OutMessage found in query) { Stream body = await bodyStore.LoadMessageBodyAsync(found.MessageLocation); AS4Message signal = await SerializerProvider .Default .Get(found.ContentType) .DeserializeAsync(body, found.ContentType); var toBePiggyBacked = signal.SignalMessages.FirstOrDefault(s => s.MessageId == found.EbmsMessageId); if (toBePiggyBacked is Receipt || toBePiggyBacked is Error) { if (!pullRequestSigned && signal.IsSigned) { Logger.Warn( $"Can't PiggyBack {toBePiggyBacked.GetType().Name} {toBePiggyBacked.MessageId} because SignalMessage is signed " + $"while the SendingPMode {sendingPMode.Id} used is not configured for signing"); } else { found.Operation = Operation.Sending; toBePiggyBackedSignals.Add(toBePiggyBacked); } } else if (toBePiggyBacked != null) { Logger.Warn( $"Will not select {toBePiggyBacked.GetType().Name} {toBePiggyBacked.MessageId} " + "for PiggyBacking because only Receipts and Errors are allowed SignalMessages to be PiggyBacked with PullRequests"); } else { Logger.Warn("Will not select AS4Message for PiggyBacking because it doesn't contains any Message Units"); } } if (toBePiggyBackedSignals.Any()) { await db.SaveChangesAsync() .ConfigureAwait(false); } return toBePiggyBackedSignals.Cast <SignalMessage>().AsEnumerable(); })); }