diff --git a/source/IncomingMessages.Infrastructure/MessageParsers/MarketMessageParser.cs b/source/IncomingMessages.Infrastructure/MessageParsers/MarketMessageParser.cs index ca77e1a29b..1cccfada17 100644 --- a/source/IncomingMessages.Infrastructure/MessageParsers/MarketMessageParser.cs +++ b/source/IncomingMessages.Infrastructure/MessageParsers/MarketMessageParser.cs @@ -52,7 +52,7 @@ public async Task ParseAsync( var parser = _parsers.FirstOrDefault(parser => parser.HandledFormat.Equals(documentFormat) && parser.DocumentType.Equals(documentType)); if (parser is null) - throw new InvalidOperationException($"No message parser found for message format '{documentFormat}' and document type '{documentType}'"); + throw new NotSupportedException($"No message parser found for message format '{documentFormat}' and document type '{documentType}'"); return await parser.ParseAsync(marketMessage, cancellationToken).ConfigureAwait(false); } } diff --git a/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/Ebix/MeteredDataForMeasurementPointEbixMessageParser.cs b/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/Ebix/MeteredDataForMeasurementPointEbixMessageParser.cs index 638d7606dd..654febd38f 100644 --- a/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/Ebix/MeteredDataForMeasurementPointEbixMessageParser.cs +++ b/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/Ebix/MeteredDataForMeasurementPointEbixMessageParser.cs @@ -12,220 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.Collections.ObjectModel; -using System.Xml; -using System.Xml.Linq; -using System.Xml.Schema; using Energinet.DataHub.EDI.BuildingBlocks.Domain.Models; -using Energinet.DataHub.EDI.IncomingMessages.Domain; -using Energinet.DataHub.EDI.IncomingMessages.Domain.Validation.ValidationErrors; -using Energinet.DataHub.EDI.IncomingMessages.Infrastructure.Schemas.Ebix; -using Microsoft.Extensions.Logging; -using MessageHeaderExtractor = Energinet.DataHub.EDI.IncomingMessages.Infrastructure.MessageParsers.BaseParsers.Ebix.MessageHeaderExtractor; namespace Energinet.DataHub.EDI.IncomingMessages.Infrastructure.MessageParsers.MeteredDateForMeasurementPointParsers.Ebix; -public class MeteredDataForMeasurementPointEbixMessageParser(EbixSchemaProvider schemaProvider, ILogger logger) : IMarketMessageParser +public class MeteredDataForMeasurementPointEbixMessageParser(MeteredDataForMeasurementPointMessageParser messageParser) : IMarketMessageParser { - private const string RootPayloadElementName = "DK_MeteredDataTimeSeries"; - private readonly EbixSchemaProvider _schemaProvider = schemaProvider; - private readonly ILogger _logger = logger; + private readonly MeteredDataForMeasurementPointMessageParser _messageParser = messageParser; public DocumentFormat HandledFormat => DocumentFormat.Ebix; public IncomingDocumentType DocumentType => IncomingDocumentType.MeteredDataForMeasurementPoint; - private Collection Errors { get; } = []; - public async Task ParseAsync( IIncomingMarketMessageStream incomingMarketMessageStream, CancellationToken cancellationToken) { - var xmlSchemaResult = await GetSchemaAsync(incomingMarketMessageStream, cancellationToken).ConfigureAwait(false); - if (xmlSchemaResult.Schema == null || xmlSchemaResult.Namespace == null) - { - return xmlSchemaResult.ParserResult ?? new IncomingMarketMessageParserResult(new InvalidSchemaOrNamespace()); - } - - using var reader = XmlReader.Create(incomingMarketMessageStream.Stream, CreateXmlReaderSettings(xmlSchemaResult.Schema)); - if (Errors.Count > 0) - { - return new IncomingMarketMessageParserResult(Errors.ToArray()); - } - - try - { - var parsedXmlData = await ParseXmlDataAsync(reader, xmlSchemaResult.Namespace, cancellationToken).ConfigureAwait(false); - - if (Errors.Count != 0) - { - _logger.LogError("Errors found after parsing XML data: {Errors}", Errors); - return new IncomingMarketMessageParserResult(Errors.ToArray()); - } - - return parsedXmlData; - } - catch (XmlException exception) - { - _logger.LogError(exception, "Ebix parsing error during data extraction"); - return InvalidEbixFailure(exception); - } - catch (ObjectDisposedException objectDisposedException) - { - _logger.LogError(objectDisposedException, "Stream was disposed during data extraction"); - return InvalidEbixFailure(objectDisposedException); - } - } - - private static IncomingMarketMessageParserResult InvalidEbixFailure( - Exception exception) - { - return new IncomingMarketMessageParserResult( - InvalidMessageStructure.From(exception)); - } - - private static string BusinessProcessType(string @namespace) - { - ArgumentNullException.ThrowIfNull(@namespace); - var split = SplitNamespace(@namespace); - if (split.Length < 5) - { - throw new XmlException($"Invalid namespace format"); - } - - var businessReason = split[4]; - var parts = businessReason.Split('-'); - return parts.Last(); - } - - private static string GetVersion(string @namespace) - { - ArgumentNullException.ThrowIfNull(@namespace); - var split = SplitNamespace(@namespace); - if (split.Length < 6) - { - throw new XmlException($"Invalid namespace format"); - } - - var version = split[5]; - return version.StartsWith('v') ? version[1..] : version; - } - - private static string[] SplitNamespace(string @namespace) - { - ArgumentNullException.ThrowIfNull(@namespace); - return @namespace.Split(':'); - } - - private static string GetNamespace(IIncomingMarketMessageStream marketMessage) - { - ArgumentNullException.ThrowIfNull(marketMessage); - - var settings = new XmlReaderSettings - { - Async = true, - IgnoreWhitespace = true, - IgnoreComments = true, - }; - - using var reader = XmlReader.Create(marketMessage.Stream, settings); - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element && reader.Name.Contains(RootPayloadElementName)) - { - return reader.NamespaceURI; - } - } - - throw new XmlException($"Namespace for element '{RootPayloadElementName}' not found."); - } - - private async Task ParseXmlDataAsync( - XmlReader reader, - string @namespace, - CancellationToken cancellationToken) - { - var document = await XDocument.LoadAsync(reader, LoadOptions.None, cancellationToken).ConfigureAwait(false); - var ns = XNamespace.Get(@namespace); - - var header = MessageHeaderExtractor.Extract(document, ns); - var listOfSeries = MeteredDataForMeasurementPointSeriesExtractor - .ParseSeries(document, ns, header.SenderId) - .ToList(); - - return new IncomingMarketMessageParserResult(new MeteredDataForMeasurementPointMessage( - header.MessageId, - header.MessageType, - header.CreatedAt, - header.SenderId, - header.ReceiverId, - header.SenderRole, - header.BusinessReason, - header.ReceiverRole, - header.BusinessType, - listOfSeries.AsReadOnly())); - } - - private async Task<(XmlSchema? Schema, string? Namespace, IncomingMarketMessageParserResult? ParserResult)> GetSchemaAsync( - IIncomingMarketMessageStream incomingMarketMessageStream, - CancellationToken cancellationToken) - { - string? @namespace = null; - IncomingMarketMessageParserResult? parserResult = null; - XmlSchema? xmlSchema = null; - try - { - @namespace = GetNamespace(incomingMarketMessageStream); - var version = GetVersion(@namespace); - var businessProcessType = BusinessProcessType(@namespace); - xmlSchema = await _schemaProvider.GetSchemaAsync(businessProcessType, version, cancellationToken) - .ConfigureAwait(true); - - if (xmlSchema is null) - { - _logger.LogError("Schema not found for business process type {BusinessProcessType} and version {Version}", businessProcessType, version); - parserResult = new IncomingMarketMessageParserResult( - new InvalidBusinessReasonOrVersion(businessProcessType, version)); - } - } - catch (XmlException exception) - { - _logger.LogWarning(exception, "Ebix parsing error"); - parserResult = InvalidEbixFailure(exception); - } - catch (ObjectDisposedException objectDisposedException) - { - _logger.LogWarning(objectDisposedException, "Stream was disposed"); - parserResult = InvalidEbixFailure(objectDisposedException); - } - catch (IndexOutOfRangeException indexOutOfRangeException) - { - _logger.LogWarning(indexOutOfRangeException, "Namespace format is invalid"); - parserResult = InvalidEbixFailure(indexOutOfRangeException); - } - - return (xmlSchema, @namespace, parserResult); - } - - private XmlReaderSettings CreateXmlReaderSettings(XmlSchema xmlSchema) - { - var settings = new XmlReaderSettings - { - Async = true, - ValidationType = ValidationType.Schema, - ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema | - XmlSchemaValidationFlags.ReportValidationWarnings, - }; - - settings.Schemas.Add(xmlSchema); - settings.ValidationEventHandler += OnValidationError; - return settings; - } - - private void OnValidationError(object? sender, ValidationEventArgs arguments) - { - var message = - $"XML schema validation error at line {arguments.Exception.LineNumber}, position {arguments.Exception.LinePosition}: {arguments.Message}."; - Errors.Add(InvalidMessageStructure.From(message)); + return await _messageParser.ParseEbixXmlAsync(incomingMarketMessageStream, cancellationToken).ConfigureAwait(false); } } diff --git a/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/MeteredDataForMeasurementPointMessageParser.cs b/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/MeteredDataForMeasurementPointMessageParser.cs index a1759026b4..31644da0ba 100644 --- a/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/MeteredDataForMeasurementPointMessageParser.cs +++ b/source/IncomingMessages.Infrastructure/MessageParsers/MeteredDateForMeasurementPointParsers/MeteredDataForMeasurementPointMessageParser.cs @@ -24,11 +24,11 @@ public partial class MeteredDataForMeasurementPointMessageParser : IMessageParse public Task ParseXmlAsync(IIncomingMarketMessageStream incomingMarketMessageStream, CancellationToken cancellationToken) { - throw new NotImplementedException(); + throw new NotSupportedException(); } public Task ParseJsonAsync(IIncomingMarketMessageStream incomingMarketMessageStream, CancellationToken cancellationToken) { - throw new NotImplementedException(); + throw new NotSupportedException(); } } diff --git a/source/IncomingMessages.IntegrationTests/MessageParsers/GivenNewDocumentTypeTests.cs b/source/IncomingMessages.IntegrationTests/MessageParsers/GivenNewDocumentTypeTests.cs index 4eade98878..fa9e63654d 100644 --- a/source/IncomingMessages.IntegrationTests/MessageParsers/GivenNewDocumentTypeTests.cs +++ b/source/IncomingMessages.IntegrationTests/MessageParsers/GivenNewDocumentTypeTests.cs @@ -84,7 +84,7 @@ public async Task When_ParsingMessageOfDocumentTypeAndFormat_Then_ExpectedMessag // Assert if (_unsupportedCombinationsOfIncomingDocumentTypeAndDocumentFormat.Contains((incomingDocumentType, documentFormat))) { - await act.Should().ThrowAsync("because this combination is not supported"); + await act.Should().ThrowAsync("because this combination is not supported"); } else { diff --git a/source/Tests/CimMessageAdapter/Messages/MeteredDataForMeasurementPointEbixMessageParserTests/MessageParserTests.cs b/source/Tests/CimMessageAdapter/Messages/MeteredDataForMeasurementPointMessageParserTests/MessageParserTests.cs similarity index 91% rename from source/Tests/CimMessageAdapter/Messages/MeteredDataForMeasurementPointEbixMessageParserTests/MessageParserTests.cs rename to source/Tests/CimMessageAdapter/Messages/MeteredDataForMeasurementPointMessageParserTests/MessageParserTests.cs index 8926c8ce51..3fe38a0f08 100644 --- a/source/Tests/CimMessageAdapter/Messages/MeteredDataForMeasurementPointEbixMessageParserTests/MessageParserTests.cs +++ b/source/Tests/CimMessageAdapter/Messages/MeteredDataForMeasurementPointMessageParserTests/MessageParserTests.cs @@ -13,10 +13,12 @@ // limitations under the License. using System.Xml.Linq; +using Energinet.DataHub.BuildingBlocks.Tests.TestDoubles; using Energinet.DataHub.EDI.BuildingBlocks.Domain.Models; using Energinet.DataHub.EDI.IncomingMessages.Domain; using Energinet.DataHub.EDI.IncomingMessages.Domain.Validation.ValidationErrors; using Energinet.DataHub.EDI.IncomingMessages.Infrastructure.MessageParsers; +using Energinet.DataHub.EDI.IncomingMessages.Infrastructure.MessageParsers.MeteredDateForMeasurementPointParsers; using Energinet.DataHub.EDI.IncomingMessages.Infrastructure.MessageParsers.MeteredDateForMeasurementPointParsers.Ebix; using Energinet.DataHub.EDI.IncomingMessages.Infrastructure.Schemas.Ebix; using Energinet.DataHub.EDI.IncomingMessages.Interfaces.Models; @@ -25,7 +27,7 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Energinet.DataHub.EDI.Tests.CimMessageAdapter.Messages.MeteredDataForMeasurementPointEbixMessageParserTests; +namespace Energinet.DataHub.EDI.Tests.CimMessageAdapter.Messages.MeteredDataForMeasurementPointMessageParserTests; public sealed class MessageParserTests { @@ -36,9 +38,14 @@ public sealed class MessageParserTests $"{Path.DirectorySeparatorChar}MeteredDataForMeasurementPoint{Path.DirectorySeparatorChar}"; private readonly MarketMessageParser _marketMessageParser = new( - [ - new MeteredDataForMeasurementPointEbixMessageParser(new EbixSchemaProvider(), new Logger(new LoggerFactory())), - ]); + new List(), + new Dictionary() + { + { + IncomingDocumentType.MeteredDataForMeasurementPoint, new MeteredDataForMeasurementPointMessageParser(new EbixSchemaProvider(), new Logger(new LoggerFactory())) + }, + }, + new FeatureFlagManagerStub()); public static TheoryData CreateMessagesWithSingleAndMultipleTransactions() { diff --git a/source/Tests/CimMessageAdapter/Messages/RequestAggregatedMeasureData/MessageParserTests.cs b/source/Tests/CimMessageAdapter/Messages/RequestAggregatedMeasureData/MessageParserTests.cs index 3e374d7709..e0c67daa6a 100644 --- a/source/Tests/CimMessageAdapter/Messages/RequestAggregatedMeasureData/MessageParserTests.cs +++ b/source/Tests/CimMessageAdapter/Messages/RequestAggregatedMeasureData/MessageParserTests.cs @@ -14,6 +14,7 @@ using System.Text; using System.Xml.Linq; +using Energinet.DataHub.BuildingBlocks.Tests.TestDoubles; using Energinet.DataHub.EDI.B2CWebApi.Factories; using Energinet.DataHub.EDI.BuildingBlocks.Domain.DataHub; using Energinet.DataHub.EDI.BuildingBlocks.Domain.Models; @@ -44,11 +45,13 @@ public sealed class MessageParserTests $"{Path.DirectorySeparatorChar}aggregatedmeasure{Path.DirectorySeparatorChar}"; private readonly MarketMessageParser _marketMessageParser = new( - [ - new AggregatedMeasureDataXmlMessageParser(new CimXmlSchemaProvider(new CimXmlSchemas())), - new AggregatedMeasureDataJsonMessageParser(new JsonSchemaProvider(new CimJsonSchemas())), - new AggregatedMeasureDataB2CJsonMessageParser(new Serializer()), - ]); + [ + new AggregatedMeasureDataXmlMessageParser(new CimXmlSchemaProvider(new CimXmlSchemas())), + new AggregatedMeasureDataJsonMessageParser(new JsonSchemaProvider(new CimJsonSchemas())), + new AggregatedMeasureDataB2CJsonMessageParser(new Serializer()), + ], + new Dictionary(), + new FeatureFlagManagerStub()); public static IEnumerable CreateMessagesWithSingleAndMultipleTransactions() { diff --git a/source/Tests/CimMessageAdapter/Messages/WholesaleSettlementMessageParsers/MessageParserTests.cs b/source/Tests/CimMessageAdapter/Messages/WholesaleSettlementMessageParsers/MessageParserTests.cs index fa3f319cab..7e3e60fcde 100644 --- a/source/Tests/CimMessageAdapter/Messages/WholesaleSettlementMessageParsers/MessageParserTests.cs +++ b/source/Tests/CimMessageAdapter/Messages/WholesaleSettlementMessageParsers/MessageParserTests.cs @@ -14,6 +14,7 @@ using System.Text; using System.Xml.Linq; +using Energinet.DataHub.BuildingBlocks.Tests.TestDoubles; using Energinet.DataHub.EDI.B2CWebApi.Factories; using Energinet.DataHub.EDI.B2CWebApi.Models; using Energinet.DataHub.EDI.BuildingBlocks.Domain.Models; @@ -54,7 +55,9 @@ public MessageParserTests() new WholesaleSettlementXmlMessageParser(new CimXmlSchemaProvider(new CimXmlSchemas())), new WholesaleSettlementJsonMessageParser(new JsonSchemaProvider(new CimJsonSchemas())), new WholesaleSettlementB2CJsonMessageParser(_serializer), - ]); + ], + new Dictionary(), + new FeatureFlagManagerStub()); } public static IEnumerable CreateMessagesWithTwoChargeTypes()