// 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