blob: 91cf3e879f81084fd1113d0a2e72b07710aefd4b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 Robert Bosch GmbH
* Author: Constantin Ziesche (constantin.ziesche@bosch.com)
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
using BaSyx.Models.Core.AssetAdministrationShell.Generics;
using BaSyx.Models.Core.AssetAdministrationShell.Identification;
using BaSyx.Models.Core.AssetAdministrationShell.Implementations;
using BaSyx.Models.Core.AssetAdministrationShell.Semantics;
using BaSyx.Models.Core.Attributes;
using BaSyx.Models.Core.Common;
using BaSyx.Models.Extensions.Semantics.DataSpecifications;
using NLog;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace BaSyx.Models.Extensions
{
public static class SubmodelElementExtensions
{
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
public const BindingFlags DEFAULT_BINDING_FLAGS = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
internal static T As<T>(this IReferable referable) where T : class, IReferable
{
return referable as T;
}
public static T Cast<T>(this IReferable referable) where T : class, IReferable
{
return referable as T;
}
public static IEnumerable<T> ToEnumerable<T>(this ISubmodelElementCollection collection)
{
if (collection != null)
{
if (!collection.AllowDuplicates || !collection.Ordered)
logger.Warn($"SubmodelElementCollection {collection.IdShort} has AllowDuplicated or Ordered set to false. The next line in code could fail converting the elements to datatype IEnumerable<{typeof(T).Name}>");
return collection.Value.Select(s => s.Cast<IProperty>().ToObject<T>());
}
else
return null;
}
public static T ToEntity<T>(this ISubmodelElementCollection collection) where T : class
{
if (collection != null)
{
return new SubmodelElementCollectionOfEntity<T>(collection).Value;
}
else
return null;
}
public static IValue GetValue(this ISubmodelElement submodelElement)
{
return submodelElement?.Get?.Invoke(submodelElement);
}
public static T GetValue<T>(this ISubmodelElement submodelElement)
{
IValue value = submodelElement?.Get?.Invoke(submodelElement);
if (value != null)
return value.ToObject<T>();
else
return default;
}
public static void SetValue<T>(this ISubmodelElement submodelElement, T value)
{
if(typeof(IValue).IsAssignableFrom(typeof(T)))
submodelElement?.Set?.Invoke(submodelElement, value as IValue);
else
submodelElement?.Set?.Invoke(submodelElement, new ElementValue<T>(value));
}
public static void SetValue(this ISubmodelElement submodelElement, IValue value)
{
submodelElement?.Set?.Invoke(submodelElement, value);
}
public static void SetValue(this ISubmodelElement submodelElement, object value, DataType valueType)
{
submodelElement?.Set?.Invoke(submodelElement, new ElementValue(value, valueType));
}
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromObject(this object target)
=> CreateSubmodelElementCollectionFromType(target.GetType(), target.GetType().Name, DEFAULT_BINDING_FLAGS, target);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromObject(this object target, string idShort)
=> CreateSubmodelElementCollectionFromType(target.GetType(), idShort, BindingFlags.Public | BindingFlags.Instance, target);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromObject(this object target, BindingFlags bindingFlags)
=> CreateSubmodelElementCollectionFromType(target.GetType(), target.GetType().Name, bindingFlags, target);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromObject(this object target, string idShort, BindingFlags bindingFlags)
=> CreateSubmodelElementCollectionFromType(target.GetType(), idShort, bindingFlags, target);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromEnumerable<T>(this IEnumerable enumerable)
=> CreateSubmodelElementCollectionFromEnumerable(enumerable, typeof(T).Name, DEFAULT_BINDING_FLAGS);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromEnumerable(this IEnumerable enumerable, string idShort)
=> CreateSubmodelElementCollectionFromEnumerable(enumerable, idShort, DEFAULT_BINDING_FLAGS);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromEnumerable<T>(this IEnumerable enumerable, BindingFlags bindingFlags)
=> CreateSubmodelElementCollectionFromEnumerable(enumerable, typeof(T).Name, bindingFlags);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromEnumerable(this IEnumerable enumerable, string idShort, BindingFlags bindingFlags)
{
SubmodelElementCollection smCollection = new SubmodelElementCollection(idShort);
smCollection.AllowDuplicates = true;
smCollection.Ordered = true;
foreach (var item in enumerable)
{
foreach (var propertyInfo in item.GetType().GetProperties(bindingFlags))
{
ISubmodelElement smElement = CreateSubmodelElementFromPropertyInfo(propertyInfo, propertyInfo.Name, bindingFlags, item);
if(smElement != null)
smCollection.Value.Create(smElement);
}
}
return smCollection;
}
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromType(this Type type)
=> CreateSubmodelElementCollectionFromType(type, type.Name, DEFAULT_BINDING_FLAGS, null);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromType(this Type type, string idShort)
=> CreateSubmodelElementCollectionFromType(type, idShort, DEFAULT_BINDING_FLAGS, null);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromType(this Type type, BindingFlags bindingFlags)
=> CreateSubmodelElementCollectionFromType(type, type.Name, bindingFlags, null);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromType(this Type type, string idShort, BindingFlags bindingFlags)
=> CreateSubmodelElementCollectionFromType(type, idShort, bindingFlags, null);
public static ISubmodelElementCollection CreateSubmodelElementCollectionFromType(this Type type, string idShort, BindingFlags bindingFlags, object target)
{
Attribute attribute = Attribute.GetCustomAttribute(type, typeof(SubmodelElementCollectionAttribute), true);
SubmodelElementCollection smCollection;
if (attribute is SubmodelElementCollectionAttribute seCollectionAttribute)
{
smCollection = seCollectionAttribute.SubmodelElementCollection;
if(!string.IsNullOrEmpty(idShort) && idShort != type.Name)
smCollection.IdShort = idShort;
}
else
{
smCollection = new SubmodelElementCollection(idShort);
}
foreach (var propertyInfo in type.GetProperties(bindingFlags))
{
ISubmodelElement smElement = CreateSubmodelElementFromPropertyInfo(propertyInfo, propertyInfo.Name, bindingFlags, target);
if(smElement != null)
smCollection.Value.Create(smElement);
}
return smCollection;
}
public static ISubmodelElement CreateSubmodelElementFromPropertyInfo(this PropertyInfo propertyInfo)
=> CreateSubmodelElementFromPropertyInfo(propertyInfo, propertyInfo.Name, DEFAULT_BINDING_FLAGS, null);
public static ISubmodelElement CreateSubmodelElementFromPropertyInfo(this PropertyInfo propertyInfo, string idShort)
=> CreateSubmodelElementFromPropertyInfo(propertyInfo, idShort, DEFAULT_BINDING_FLAGS, null);
public static ISubmodelElement CreateSubmodelElementFromPropertyInfo(this PropertyInfo propertyInfo, BindingFlags bindingFlags)
=> CreateSubmodelElementFromPropertyInfo(propertyInfo, propertyInfo.Name, bindingFlags, null);
public static ISubmodelElement CreateSubmodelElementFromPropertyInfo(this PropertyInfo propertyInfo, string idShort, BindingFlags bindingFlags)
=> CreateSubmodelElementFromPropertyInfo(propertyInfo, idShort, bindingFlags, null);
public static ISubmodelElement CreateSubmodelElementFromPropertyInfo(this PropertyInfo propertyInfo, string idShort, BindingFlags bindingFlags, object target)
{
Attribute attribute = Attribute.GetCustomAttribute(propertyInfo, typeof(SubmodelElementAttribute), true);
if (attribute is SubmodelElementAttribute seAttribute)
{
SubmodelElement se = seAttribute.SubmodelElement;
if (!string.IsNullOrEmpty(idShort) && idShort != propertyInfo.Name)
se.IdShort = idShort;
if(Attribute.IsDefined(propertyInfo, typeof(DataSpecificationIEC61360Attribute)))
{
var specAttribute = Attribute.GetCustomAttribute(propertyInfo, typeof(DataSpecificationIEC61360Attribute)) as DataSpecificationIEC61360Attribute;
se.ConceptDescription = new ConceptDescription()
{
Identification = specAttribute.Identification,
EmbeddedDataSpecifications = new List<IEmbeddedDataSpecification>()
{
new DataSpecificationIEC61360(specAttribute.Content)
}
};
}
if (se is SubmodelElementCollection seCollection)
{
if (DataType.IsGenericList(propertyInfo.PropertyType) || DataType.IsArray(propertyInfo.PropertyType))
{
ISubmodelElementCollection tempSeCollection;
if (target != null && propertyInfo.CanRead && propertyInfo.GetValue(target) is IEnumerable enumerable)
tempSeCollection = enumerable.CreateSubmodelElementCollectionFromEnumerable(idShort, bindingFlags);
else
tempSeCollection = new SubmodelElementCollection(idShort);
seCollection.Value.AddRange(tempSeCollection.Value);
return seCollection;
}
else
{
object subTarget = null;
if (target != null && propertyInfo.CanRead)
subTarget = propertyInfo.GetValue(target);
foreach (var subPropertyInfo in propertyInfo.PropertyType.GetProperties(bindingFlags))
{
ISubmodelElement smElement = CreateSubmodelElementFromPropertyInfo(subPropertyInfo, subPropertyInfo.Name, bindingFlags, subTarget);
if (smElement != null)
seCollection.Value.Create(smElement);
}
}
return seCollection;
}
else if (se is Property seProp)
{
if (target != null && propertyInfo.CanRead)
seProp.Value = propertyInfo.GetValue(target);
return seProp;
}
else
{
return se;
}
}
else if (Attribute.IsDefined(propertyInfo, typeof(IgnoreElementAttribute)))
return null;
else
{
DataType dataType = DataType.GetDataTypeFromSystemType(propertyInfo.PropertyType);
if (dataType == null)
{
logger.Warn($"Unable to convert system type {propertyInfo.PropertyType} to DataType");
return null;
}
IConceptDescription conceptDescription = null;
if (Attribute.IsDefined(propertyInfo, typeof(DataSpecificationIEC61360Attribute)))
{
var specAttribute = Attribute.GetCustomAttribute(propertyInfo, typeof(DataSpecificationIEC61360Attribute)) as DataSpecificationIEC61360Attribute;
conceptDescription = new ConceptDescription()
{
Identification = specAttribute.Identification,
EmbeddedDataSpecifications = new List<IEmbeddedDataSpecification>()
{
new DataSpecificationIEC61360(specAttribute.Content)
}
};
}
if (DataType.IsSimpleType(propertyInfo.PropertyType))
{
Property smProp = new Property(idShort, dataType);
if (target != null && propertyInfo.CanRead)
smProp.Value = propertyInfo.GetValue(target);
smProp.ConceptDescription = conceptDescription;
return smProp;
}
else if (propertyInfo.PropertyType == typeof(DateTime))
{
Property smProp = new Property(idShort, new DataType(DataObjectType.DateTime));
if (target != null && propertyInfo.CanRead && propertyInfo.GetValue(target) is DateTime dateTime)
smProp.Value = dateTime;
smProp.ConceptDescription = conceptDescription;
return smProp;
}
else if (DataType.IsGenericList(propertyInfo.PropertyType) || DataType.IsArray(propertyInfo.PropertyType))
{
SubmodelElementCollection seCollection;
if (target != null && propertyInfo.CanRead && propertyInfo.GetValue(target) is IEnumerable enumerable)
seCollection = (SubmodelElementCollection)enumerable.CreateSubmodelElementCollectionFromEnumerable(idShort, bindingFlags);
else
seCollection = new SubmodelElementCollection(idShort);
seCollection.AllowDuplicates = true;
seCollection.Ordered = true;
seCollection.ConceptDescription = conceptDescription;
return seCollection;
}
else
{
SubmodelElementCollection smCollection = new SubmodelElementCollection(idShort);
object subTarget = null;
if (target != null && propertyInfo.CanRead)
subTarget = propertyInfo.GetValue(target);
foreach (var subPropertyInfo in dataType.SystemType.GetProperties(bindingFlags))
{
ISubmodelElement smElement = CreateSubmodelElementFromPropertyInfo(subPropertyInfo, subPropertyInfo.Name, bindingFlags, subTarget);
if (smElement != null)
smCollection.Value.Create(smElement);
}
smCollection.AllowDuplicates = false;
smCollection.Ordered = false;
smCollection.ConceptDescription = conceptDescription;
return smCollection;
}
}
}
}
}