// Copyright (C) Stichting Deltares 2024. All rights reserved. // // This file is part of the Dam Engine. // // The Dam Engine is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Xml.Linq; namespace Deltares.DamEngine.Calculators.KernelWrappers.Assemblers; #region DtoAssembler definition /// /// Default implementation for the interface /// /// The domain object type public abstract class DtoAssembler : IDtoAssembler where TDomainObject : new() { /// /// Holds the property mappings /// private readonly DtoPropertyAttributeMap map = new DtoPropertyAttributeMap(); /// /// Gets the property mappings collection /// protected DtoPropertyAttributeMap Mappings { get { return map; } } /// /// /// protected void InitializeMappings() { var tmp = new TDomainObject(); map.AddOrUpdateRange(tmp.ToPropertyMap()); } /// /// /// protected void InitializeMappings(string elementName, XDocument xsdReferenceDocument) { var tmp = new TDomainObject(); IEnumerable tmpMap = tmp.ToPropertyMap(elementName, xsdReferenceDocument); map.AddOrUpdateRange(tmpMap); } /// /// Adds or updates a property-to-attribute mapping item into the property map /// /// The name of the property /// The name of the attribute to map to protected void AddOrUpdateMapping(string propertyName, string attributeName) { AddOrUpdateMapping(propertyName, attributeName, DtoPropertyImportance.Optional); } /// /// Adds or updates a property-to-attribute mapping item into the property map /// /// The name of the property /// The name of the attribute to map to /// The usage or importance of the value i.e. reguired or optional protected void AddOrUpdateMapping(string propertyName, string attributeName, DtoPropertyImportance importance) { if (!propertyName.HasValidStringValue()) { throw new DtoPropertyMapException("propertyName is not valid (empty or null)"); } bool q = (from x in new TDomainObject().GetType().GetProperties() where x.Name == propertyName select x).Any(); if (!q) { throw new DtoPropertyMapException("The property you want to add or update doesnt exist in the property list of the domain object."); } Mappings.AddOrUpdate(propertyName, attributeName, importance); } #region IDtoAssembler Members /// /// /// /// /// public abstract TDomainObject CreateDomainObject(TDataTransferObject dtoObj); /// /// /// /// /// public abstract TDataTransferObject CreateDataTransferObject(TDomainObject domainObj); #endregion } #endregion #region DtoAssembler /// /// Default implementation for the interface /// /// /// This base class inherits from this class just fixes /// the dto type to XElement /// /// The domain object type public abstract class DtoAssembler : DtoAssembler, IDtoAssembler where TDomainObject : new() { /// /// Initializes a new instance of the DtoAssembler class /// /// Sets the element name /// The text reader stream for reading in ther xsd file which is embedded as an resource public DtoAssembler(string elementName, Stream xsdStream) : this(elementName, null, xsdStream) {} /// /// Initializes a new instance of the DtoAssembler class /// /// Sets the element name /// The text reader stream for reading in ther xsd file which is embedded as an resource public DtoAssembler(string elementName, string elementNamespace) : this(elementName, elementNamespace, null) {} /// /// Initializes a new instance of the DtoAssembler class /// /// Sets the element name /// The text reader stream for reading in ther xsd file which is embedded as an resource public DtoAssembler(string elementName, string elementNamespace, Stream xsdStream) { ElementName = elementName; ElementNamespace = elementNamespace; if (xsdStream == null) { xsdStream = GetXsdStreamFromEmbeddedResource(); } XDocument doc = XDocument.Load(new StreamReader(xsdStream)); Schema = doc; InitializeMappings(elementName, doc); } /// /// Gets or sets the namespace value for the element /// public string ElementNamespace { get; } /// /// Gets the xml schema (if any) /// public XDocument Schema { get; } public Stream GetXsdStreamFromEmbeddedResource() { if (string.IsNullOrEmpty(ElementNamespace)) { return null; } Assembly assembly = GetType().Assembly; string schemaName = ElementNamespace.Substring(ElementNamespace.LastIndexOf('/') + 1); schemaName += schemaName.EndsWith(".xsd") ? "" : ".xsd"; string resourceName = (from string name in assembly.GetManifestResourceNames() where name.EndsWith(schemaName) select name).Single(); return assembly.GetEmbeddedFile(resourceName); } public virtual TDomainObject CreateDomainObject(XDocument dtoDocument) { if (dtoDocument == null) { throw new ArgumentNullException("dtoDocument"); } XElement el = null; el = (from x in dtoDocument.Descendants() where x.Name.LocalName == ElementName select x).Single(); return CreateDomainObject(el); } #region IDtoAssembler Members /// /// Gets the xml element name /// public string ElementName { get; } /// /// Creates and materialized a data tranfer object (dto) from a domain object /// /// The domain object /// An XElement instance public override XElement CreateDataTransferObject(TDomainObject domainObj) { if (!typeof(TDomainObject).IsValueType && (domainObj == null)) { return null; } if (!ElementName.HasValidStringValue()) { throw new DtoAssemblerException("There is no element name specified"); } if (ElementNamespace.HasValidStringValue()) { XNamespace ns = ElementNamespace; return new XElement(ns + ElementName) .Materialize(domainObj, Mappings); } return new XElement(ElementName) .Materialize(domainObj, Mappings); } /// /// Creates and materializes a domain object from a data tranfer object (dto) /// /// The dto object /// The materialized domain object public override TDomainObject CreateDomainObject(XElement dto) { return new TDomainObject().Materialize(dto, Mappings); } #endregion } #endregion