From 4b1cb2d9d52c3923540dadcbbd688022ed5e7472 Mon Sep 17 00:00:00 2001 From: Patrick Ritchie Date: Tue, 24 Oct 2023 20:48:57 -0400 Subject: [PATCH] Added SysML project --- src/MTConnect.NET-SysML/CSharp/ClassModel.cs | 122 +++ .../CSharp/ComponentType.cs | 83 ++ .../CSharp/CompositionType.cs | 83 ++ .../CSharp/DataItemType.cs | 87 +++ src/MTConnect.NET-SysML/CSharp/EnumModel.cs | 78 ++ .../CSharp/EnumStringModel.cs | 78 ++ .../CSharp/ITemplateModel.cs | 11 + .../CSharp/NamespaceHelper.cs | 22 + .../CSharp/TemplateRenderer.cs | 147 ++++ .../Assets.CuttingToolMeasurement.scriban | 37 + .../Templates/Devices.ComponentType.scriban | 24 + .../Templates/Devices.CompositionType.scriban | 22 + .../Templates/Devices.DataItemType.scriban | 90 +++ .../CSharp/Templates/Devices.Device.scriban | 736 ++++++++++++++++++ .../CSharp/Templates/Enum.scriban | 17 + .../CSharp/Templates/EnumString.scriban | 17 + .../CSharp/Templates/Interface.scriban | 21 + .../CSharp/Templates/Model.scriban | 25 + .../Observations.Observation.scriban | 20 + src/MTConnect.NET-SysML/CSharp/UnitsHelper.cs | 17 + .../Extensions/ListExtensions.cs | 44 ++ .../Extensions/StringFunctions.cs | 576 ++++++++++++++ .../IMTConnectExportModel.cs | 9 + .../MTConnect.NET-SysML.csproj | 42 + .../MTConnectClassModel.cs | 101 +++ src/MTConnect.NET-SysML/MTConnectEnumModel.cs | 61 ++ .../MTConnectEnumValueModel.cs | 37 + src/MTConnect.NET-SysML/MTConnectModel.cs | 39 + .../MTConnectPackageModel.cs | 11 + .../MTConnectPropertyModel.cs | 103 +++ .../MTConnectSubclassModel.cs | 33 + src/MTConnect.NET-SysML/MTConnectVersion.cs | 78 ++ src/MTConnect.NET-SysML/ModelHelper.cs | 412 ++++++++++ .../Assets/MTConnectAssetInformationModel.cs | 183 +++++ .../Models/Assets/MTConnectAssetModel.cs | 16 + .../MTConnectCuttingToolMeasurementModel.cs | 83 ++ .../Models/Devices/MTConnectComponentModel.cs | 17 + .../Models/Devices/MTConnectComponentType.cs | 79 ++ .../Devices/MTConnectComponentsModel.cs | 11 + .../Devices/MTConnectCompositionModel.cs | 20 + .../Devices/MTConnectCompositionType.cs | 64 ++ .../Devices/MTConnectCompositionsModel.cs | 11 + .../Devices/MTConnectConfigurationModel.cs | 15 + .../Models/Devices/MTConnectDataItemModel.cs | 33 + .../Devices/MTConnectDataItemSubType.cs | 27 + .../Models/Devices/MTConnectDataItemType.cs | 148 ++++ .../Models/Devices/MTConnectDataItemsModel.cs | 15 + .../Devices/MTConnectDescriptionModel.cs | 10 + .../MTConnectDeviceInformationModel.cs | 162 ++++ .../Models/Devices/MTConnectDeviceModel.cs | 32 + .../MTConnectObservationInformationModel.cs | 52 ++ .../Observations/MTConnectObservationModel.cs | 75 ++ .../MTConnectObservationValueModel.cs | 35 + .../Xmi/AnnotatedElement.cs | 18 + src/MTConnect.NET-SysML/Xmi/Association.cs | 18 + .../Xmi/ConstrainedElement.cs | 18 + src/MTConnect.NET-SysML/Xmi/DefaultValue.cs | 14 + src/MTConnect.NET-SysML/Xmi/Generalization.cs | 14 + src/MTConnect.NET-SysML/Xmi/IXmiElement.cs | 23 + src/MTConnect.NET-SysML/Xmi/LowerValue.cs | 18 + src/MTConnect.NET-SysML/Xmi/MemberEnd.cs | 18 + .../Xmi/MetamodelReference.cs | 18 + src/MTConnect.NET-SysML/Xmi/ModelExtension.cs | 24 + src/MTConnect.NET-SysML/Xmi/OwnedAttribute.cs | 14 + src/MTConnect.NET-SysML/Xmi/OwnedComment.cs | 31 + src/MTConnect.NET-SysML/Xmi/OwnedEnd.cs | 40 + src/MTConnect.NET-SysML/Xmi/OwnedLiteral.cs | 11 + src/MTConnect.NET-SysML/Xmi/OwnedOperation.cs | 36 + src/MTConnect.NET-SysML/Xmi/OwnedParameter.cs | 24 + src/MTConnect.NET-SysML/Xmi/OwnedRule.cs | 18 + src/MTConnect.NET-SysML/Xmi/PackageImport.cs | 14 + .../Xmi/PackagedElement.cs | 22 + .../Xmi/PackagedElementCollection.cs | 176 +++++ .../Xmi/Profile/Deprecated.cs | 25 + .../Xmi/Profile/Extensible.cs | 19 + .../Xmi/Profile/Informative.cs | 19 + .../Xmi/Profile/Normative.cs | 25 + .../Xmi/Profile/Observes.cs | 19 + .../Xmi/Profile/Organizer.cs | 19 + .../Xmi/Profile/ProfileElement.cs | 16 + .../Xmi/Profile/ValueType.cs | 19 + .../Xmi/RedefinedProperty.cs | 18 + src/MTConnect.NET-SysML/Xmi/Specification.cs | 26 + .../Xmi/SubsettedProperty.cs | 18 + src/MTConnect.NET-SysML/Xmi/Type.cs | 18 + .../Xmi/UML/UmlAssociation.cs | 20 + .../Xmi/UML/UmlAssociationClass.cs | 18 + src/MTConnect.NET-SysML/Xmi/UML/UmlClass.cs | 45 ++ src/MTConnect.NET-SysML/Xmi/UML/UmlComment.cs | 16 + .../Xmi/UML/UmlConstraint.cs | 18 + .../Xmi/UML/UmlDataType.cs | 39 + .../Xmi/UML/UmlEnumeration.cs | 27 + .../Xmi/UML/UmlEnumerationLiteral.cs | 21 + .../Xmi/UML/UmlExtension.cs | 28 + .../Xmi/UML/UmlExtensionEnd.cs | 15 + .../Xmi/UML/UmlGeneralization.cs | 21 + .../Xmi/UML/UmlInstanceValue.cs | 21 + .../Xmi/UML/UmlLiteralString.cs | 21 + src/MTConnect.NET-SysML/Xmi/UML/UmlModel.cs | 60 ++ .../Xmi/UML/UmlOpaqueExpression.cs | 15 + src/MTConnect.NET-SysML/Xmi/UML/UmlPackage.cs | 125 +++ .../Xmi/UML/UmlPackageImport.cs | 21 + .../Xmi/UML/UmlPrimitiveType.cs | 15 + src/MTConnect.NET-SysML/Xmi/UML/UmlProfile.cs | 56 ++ .../Xmi/UML/UmlProperty.cs | 136 ++++ .../Xmi/UML/UmlStereotype.cs | 27 + src/MTConnect.NET-SysML/Xmi/UpperValue.cs | 18 + .../Xmi/XmiDeserializer.cs | 92 +++ src/MTConnect.NET-SysML/Xmi/XmiDocument.cs | 37 + .../Xmi/XmiDocumentation.cs | 24 + src/MTConnect.NET-SysML/Xmi/XmiElement.cs | 28 + src/MTConnect.NET-SysML/Xmi/XmiExporter.cs | 18 + .../Xmi/XmiExporterVersion.cs | 18 + src/MTConnect.NET-SysML/Xmi/XmiExtension.cs | 18 + src/MTConnect.NET-SysML/Xmi/XmiHelper.cs | 184 +++++ src/MTConnect.NET.sln | 8 + 116 files changed, 6391 insertions(+) create mode 100644 src/MTConnect.NET-SysML/CSharp/ClassModel.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/ComponentType.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/CompositionType.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/DataItemType.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/EnumModel.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/EnumStringModel.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/ITemplateModel.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/NamespaceHelper.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/TemplateRenderer.cs create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Assets.CuttingToolMeasurement.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Devices.ComponentType.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Devices.CompositionType.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Devices.DataItemType.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Devices.Device.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Enum.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/EnumString.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Interface.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Model.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/Templates/Observations.Observation.scriban create mode 100644 src/MTConnect.NET-SysML/CSharp/UnitsHelper.cs create mode 100644 src/MTConnect.NET-SysML/Extensions/ListExtensions.cs create mode 100644 src/MTConnect.NET-SysML/Extensions/StringFunctions.cs create mode 100644 src/MTConnect.NET-SysML/IMTConnectExportModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnect.NET-SysML.csproj create mode 100644 src/MTConnect.NET-SysML/MTConnectClassModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectEnumModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectEnumValueModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectPackageModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectPropertyModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectSubclassModel.cs create mode 100644 src/MTConnect.NET-SysML/MTConnectVersion.cs create mode 100644 src/MTConnect.NET-SysML/ModelHelper.cs create mode 100644 src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetInformationModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Assets/MTConnectCuttingToolMeasurementModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentType.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentsModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionType.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionsModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectConfigurationModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemSubType.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemType.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemsModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDescriptionModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceInformationModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationInformationModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationModel.cs create mode 100644 src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationValueModel.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/AnnotatedElement.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Association.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/ConstrainedElement.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/DefaultValue.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Generalization.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/IXmiElement.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/LowerValue.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/MemberEnd.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/MetamodelReference.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/ModelExtension.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedAttribute.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedComment.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedEnd.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedLiteral.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedOperation.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedParameter.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/OwnedRule.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/PackageImport.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/PackagedElement.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/PackagedElementCollection.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/Deprecated.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/Extensible.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/Informative.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/Normative.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/Observes.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/Organizer.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/ProfileElement.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Profile/ValueType.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/RedefinedProperty.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Specification.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/SubsettedProperty.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/Type.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlAssociation.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlAssociationClass.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlClass.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlComment.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlConstraint.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlDataType.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlEnumeration.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlEnumerationLiteral.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlExtension.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlExtensionEnd.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlGeneralization.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlInstanceValue.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlLiteralString.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlModel.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlOpaqueExpression.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlPackage.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlPackageImport.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlPrimitiveType.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlProfile.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlProperty.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UML/UmlStereotype.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/UpperValue.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiDeserializer.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiDocument.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiDocumentation.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiElement.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiExporter.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiExporterVersion.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiExtension.cs create mode 100644 src/MTConnect.NET-SysML/Xmi/XmiHelper.cs diff --git a/src/MTConnect.NET-SysML/CSharp/ClassModel.cs b/src/MTConnect.NET-SysML/CSharp/ClassModel.cs new file mode 100644 index 00000000..6e45b226 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/ClassModel.cs @@ -0,0 +1,122 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using Scriban; +using System; +using System.IO; +using System.Linq; + +namespace MTConnect.SysML.CSharp +{ + internal class ClassModel : MTConnectClassModel, ITemplateModel + { + public string Namespace => NamespaceHelper.GetNamespace(Id); + + public bool IsPartial { get; set; } + + public string MaximumVersionEnum => MTConnectVersion.GetVersionEnum(MaximumVersion); + + public string MinimumVersionEnum => MTConnectVersion.GetVersionEnum(MinimumVersion); + + + public ClassModel() { } + + public ClassModel(XmiDocument xmiDocument, string id, UmlClass umlClass) : base(xmiDocument, id, umlClass) { } + + + public static ClassModel Create(MTConnectClassModel importModel) + { + if (importModel != null) + { + var type = typeof(ClassModel); + + var importProperties = importModel.GetType().GetProperties(); + var exportProperties = type.GetProperties(); + + if (importProperties != null && exportProperties != null) + { + var exportModel = new ClassModel(); + + foreach (var importProperty in importProperties) + { + var propertyValue = importProperty.GetValue(importModel); + + var exportProperty = exportProperties.FirstOrDefault(o => o.Name == importProperty.Name); + if (exportProperty != null) + { + exportProperty.SetValue(exportModel, propertyValue); + } + } + + foreach (var propertyModel in exportModel.Properties) + { + // Convert to Interface + if (propertyModel.DataType.ToLower() != propertyModel.DataType && propertyModel.DataType != "System.DateTime" && !propertyModel.DataType.EndsWith("Enum")) + { + if (!propertyModel.DataType.StartsWith("I")) propertyModel.DataType = $"I{propertyModel.DataType}"; + } + + // Remove 'Enum' suffix + if (propertyModel.DataType.EndsWith("Enum")) + { + var suffix = "Enum"; + if (propertyModel.DataType.EndsWith(suffix)) propertyModel.DataType = propertyModel.DataType.Substring(0, propertyModel.DataType.Length - suffix.Length); + } + } + + return exportModel; + } + } + + return null; + } + + + public string RenderModel() + { + var templateFilename = $"Model.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + + public string RenderInterface() + { + var templateFilename = $"Interface.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/ComponentType.cs b/src/MTConnect.NET-SysML/CSharp/ComponentType.cs new file mode 100644 index 00000000..3951a32a --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/ComponentType.cs @@ -0,0 +1,83 @@ +using MTConnect.SysML.Models.Devices; +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using Scriban; +using System; +using System.IO; +using System.Linq; + +namespace MTConnect.SysML.CSharp +{ + public class ComponentType : MTConnectComponentType, ITemplateModel + { + public string Namespace => NamespaceHelper.GetNamespace(Id); + + public string MaximumVersionEnum => MTConnectVersion.GetVersionEnum(MaximumVersion); + + public string MinimumVersionEnum => MTConnectVersion.GetVersionEnum(MinimumVersion); + + + public ComponentType() { } + + public ComponentType(XmiDocument xmiDocument, string idPrefix, UmlClass umlClass) : base (xmiDocument, idPrefix, umlClass) { } + + + public static ComponentType Create(MTConnectComponentType importModel) + { + if (importModel != null) + { + var type = typeof(ComponentType); + + var importProperties = importModel.GetType().GetProperties(); + var exportProperties = type.GetProperties(); + + if (importProperties != null && exportProperties != null) + { + var exportModel = new ComponentType(); + + foreach (var importProperty in importProperties) + { + var propertyValue = importProperty.GetValue(importModel); + + var exportProperty = exportProperties.FirstOrDefault(o => o.Name == importProperty.Name); + if (exportProperty != null) + { + exportProperty.SetValue(exportModel, propertyValue); + } + } + + return exportModel; + } + } + + return null; + } + + + public string RenderModel() + { + var templateFilename = $"Devices.ComponentType.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + + public string RenderInterface() => null; + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/CompositionType.cs b/src/MTConnect.NET-SysML/CSharp/CompositionType.cs new file mode 100644 index 00000000..bb85f206 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/CompositionType.cs @@ -0,0 +1,83 @@ +using MTConnect.SysML.Models.Devices; +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using Scriban; +using System; +using System.IO; +using System.Linq; + +namespace MTConnect.SysML.CSharp +{ + public class CompositionType : MTConnectCompositionType, ITemplateModel + { + public string Namespace => NamespaceHelper.GetNamespace(Id); + + public string MaximumVersionEnum => MTConnectVersion.GetVersionEnum(MaximumVersion); + + public string MinimumVersionEnum => MTConnectVersion.GetVersionEnum(MinimumVersion); + + + public CompositionType() { } + + public CompositionType(XmiDocument xmiDocument, string idPrefix, UmlEnumerationLiteral umlEnumerationLiteral) : base (xmiDocument, idPrefix, umlEnumerationLiteral) { } + + + public static CompositionType Create(MTConnectCompositionType importModel) + { + if (importModel != null) + { + var type = typeof(CompositionType); + + var importProperties = importModel.GetType().GetProperties(); + var exportProperties = type.GetProperties(); + + if (importProperties != null && exportProperties != null) + { + var exportModel = new CompositionType(); + + foreach (var importProperty in importProperties) + { + var propertyValue = importProperty.GetValue(importModel); + + var exportProperty = exportProperties.FirstOrDefault(o => o.Name == importProperty.Name); + if (exportProperty != null) + { + exportProperty.SetValue(exportModel, propertyValue); + } + } + + return exportModel; + } + } + + return null; + } + + + public string RenderModel() + { + var templateFilename = $"Devices.CompositionType.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + + public string RenderInterface() => null; + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/DataItemType.cs b/src/MTConnect.NET-SysML/CSharp/DataItemType.cs new file mode 100644 index 00000000..702edecb --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/DataItemType.cs @@ -0,0 +1,87 @@ +using MTConnect.SysML.Models.Devices; +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using Scriban; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MTConnect.SysML.CSharp +{ + public class DataItemType : MTConnectDataItemType, ITemplateModel + { + public string Namespace => NamespaceHelper.GetNamespace(Id); + + public string UnitsEnum => Units != null ? $"Devices.Units.{Units}" : null; + + public string MaximumVersionEnum => MTConnectVersion.GetVersionEnum(MaximumVersion); + + public string MinimumVersionEnum => MTConnectVersion.GetVersionEnum(MinimumVersion); + + + public DataItemType() { } + + public DataItemType(XmiDocument xmiDocument, string category, string idPrefix, UmlClass umlClass, UmlEnumerationLiteral umlEnumerationLiteral, IEnumerable subClasses = null) + : base (xmiDocument, category, idPrefix, umlClass, umlEnumerationLiteral, subClasses) { } + + + public static DataItemType Create(MTConnectDataItemType importModel) + { + if (importModel != null) + { + var type = typeof(DataItemType); + + var importProperties = importModel.GetType().GetProperties(); + var exportProperties = type.GetProperties(); + + if (importProperties != null && exportProperties != null) + { + var exportModel = new DataItemType(); + + foreach (var importProperty in importProperties) + { + var propertyValue = importProperty.GetValue(importModel); + + var exportProperty = exportProperties.FirstOrDefault(o => o.Name == importProperty.Name); + if (exportProperty != null) + { + exportProperty.SetValue(exportModel, propertyValue); + } + } + + return exportModel; + } + } + + return null; + } + + + public string RenderModel() + { + var templateFilename = $"Devices.DataItemType.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + + public string RenderInterface() => null; + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/EnumModel.cs b/src/MTConnect.NET-SysML/CSharp/EnumModel.cs new file mode 100644 index 00000000..3abf1c5e --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/EnumModel.cs @@ -0,0 +1,78 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using Scriban; +using System; +using System.IO; +using System.Linq; + +namespace MTConnect.SysML.CSharp +{ + internal class EnumModel : MTConnectEnumModel, ITemplateModel + { + public string Namespace => NamespaceHelper.GetNamespace(Id); + + + public EnumModel() { } + + public EnumModel(XmiDocument xmiDocument, string id, UmlEnumeration umlEnumeration) : base(xmiDocument, id, umlEnumeration) { } + + + public static EnumModel Create(MTConnectEnumModel importModel) + { + if (importModel != null) + { + var type = typeof(EnumModel); + + var importProperties = importModel.GetType().GetProperties(); + var exportProperties = type.GetProperties(); + + if (importProperties != null && exportProperties != null) + { + var exportModel = new EnumModel(); + + foreach (var importProperty in importProperties) + { + var propertyValue = importProperty.GetValue(importModel); + + var exportProperty = exportProperties.FirstOrDefault(o => o.Name == importProperty.Name); + if (exportProperty != null) + { + exportProperty.SetValue(exportModel, propertyValue); + } + } + + return exportModel; + } + } + + return null; + } + + + public string RenderModel() + { + var templateFilename = $"Enum.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + + public string RenderInterface() => null; + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/EnumStringModel.cs b/src/MTConnect.NET-SysML/CSharp/EnumStringModel.cs new file mode 100644 index 00000000..805939ad --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/EnumStringModel.cs @@ -0,0 +1,78 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using Scriban; +using System; +using System.IO; +using System.Linq; + +namespace MTConnect.SysML.CSharp +{ + internal class EnumStringModel : MTConnectEnumModel, ITemplateModel + { + public string Namespace => NamespaceHelper.GetNamespace(Id); + + + public EnumStringModel() { } + + public EnumStringModel(XmiDocument xmiDocument, string id, UmlEnumeration umlEnumeration) : base(xmiDocument, id, umlEnumeration) { } + + + public static EnumStringModel Create(MTConnectEnumModel importModel) + { + if (importModel != null) + { + var type = typeof(EnumStringModel); + + var importProperties = importModel.GetType().GetProperties(); + var exportProperties = type.GetProperties(); + + if (importProperties != null && exportProperties != null) + { + var exportModel = new EnumStringModel(); + + foreach (var importProperty in importProperties) + { + var propertyValue = importProperty.GetValue(importModel); + + var exportProperty = exportProperties.FirstOrDefault(o => o.Name == importProperty.Name); + if (exportProperty != null) + { + exportProperty.SetValue(exportModel, propertyValue); + } + } + + return exportModel; + } + } + + return null; + } + + + public string RenderModel() + { + var templateFilename = $"EnumString.scriban"; + var templatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csharp", "templates", templateFilename); + if (File.Exists(templatePath)) + { + try + { + var templateContents = File.ReadAllText(templatePath); + if (templateContents != null) + { + var template = Template.Parse(templateContents); + return template.Render(this); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + return null; + } + + public string RenderInterface() => null; + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/ITemplateModel.cs b/src/MTConnect.NET-SysML/CSharp/ITemplateModel.cs new file mode 100644 index 00000000..d847b08e --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/ITemplateModel.cs @@ -0,0 +1,11 @@ +namespace MTConnect.SysML.CSharp +{ + public interface ITemplateModel + { + string Id { get; } + + string RenderModel(); + + string RenderInterface(); + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/NamespaceHelper.cs b/src/MTConnect.NET-SysML/CSharp/NamespaceHelper.cs new file mode 100644 index 00000000..137bee97 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/NamespaceHelper.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace MTConnect.SysML.CSharp +{ + internal static class NamespaceHelper + { + public static string GetNamespace(string id) + { + if (!string.IsNullOrEmpty(id)) + { + var nsParts = new List(); + + var idParts = id.Split('.'); + for (var i = 0; i < idParts.Length - 1; i++) nsParts.Add(idParts[i]); + + return $"MTConnect.{string.Join('.', nsParts)}"; + } + + return null; + } + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/TemplateRenderer.cs b/src/MTConnect.NET-SysML/CSharp/TemplateRenderer.cs new file mode 100644 index 00000000..ca8fee06 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/TemplateRenderer.cs @@ -0,0 +1,147 @@ +using MTConnect.SysML.Models.Devices; +using System.Collections; +using System.Collections.Generic; +using System.IO; + +namespace MTConnect.SysML.CSharp +{ + public static class CSharpTemplateRenderer + { + public static void Render(MTConnectModel mtconnectModel, string outputPath) + { + if (mtconnectModel != null && !string.IsNullOrEmpty(outputPath)) + { + var exportModels = GetExportModels(mtconnectModel); + if (exportModels != null) + { + var templates = new List(); + + foreach (var exportModel in exportModels) + { + var type = exportModel.GetType(); + + ITemplateModel template = null; + + if (typeof(MTConnectDataItemType).IsAssignableFrom(type)) template = DataItemType.Create((MTConnectDataItemType)exportModel); + else if (typeof(MTConnectCompositionType).IsAssignableFrom(type)) template = CompositionType.Create((MTConnectCompositionType)exportModel); + else if (typeof(MTConnectComponentType).IsAssignableFrom(type)) template = ComponentType.Create((MTConnectComponentType)exportModel); + else if (typeof(MTConnectClassModel).IsAssignableFrom(type)) template = ClassModel.Create((MTConnectClassModel)exportModel); + else if (typeof(MTConnectEnumModel).IsAssignableFrom(type)) + { + switch (exportModel.Id) + { + case "Devices.UnitsEnum": template = EnumStringModel.Create((MTConnectEnumModel)exportModel); break; + case "Devices.NativeUnitsEnum": template = EnumStringModel.Create((MTConnectEnumModel)exportModel); break; + default: template = EnumModel.Create((MTConnectEnumModel)exportModel); break; + } + } + + if (template != null) + { + switch (exportModel.Id) + { + case "Devices.Device": ((ClassModel)template).IsPartial = true; break; + case "Devices.Component": ((ClassModel)template).IsPartial = true; break; + case "Devices.Composition": ((ClassModel)template).IsPartial = true; break; + case "Devices.DataItem": ((ClassModel)template).IsPartial = true; break; + case "Assets.Asset": ((ClassModel)template).IsPartial = true; break; + } + + templates.Add(template); + } + } + + if (templates != null) + { + foreach (var template in templates) + { + WriteModel(template, outputPath); + WriteInterface(template, outputPath); + } + } + } + } + } + + + private static IEnumerable GetExportModels(object model) + { + var exportModels = new List(); + + if (model != null) + { + var modelType = model.GetType(); + + if (typeof(IMTConnectExportModel).IsAssignableFrom(modelType)) + { + exportModels.Add((IMTConnectExportModel)model); + } + + var properties = modelType.GetProperties(); + if (properties != null) + { + foreach (var property in properties) + { + var propertyValue = property.GetValue(model); + if (propertyValue != null) + { + if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) + { + IEnumerable childValues = (IEnumerable)propertyValue; + foreach (var childValue in childValues) + { + exportModels.AddRange(GetExportModels(childValue)); + } + } + else + { + exportModels.AddRange(GetExportModels(propertyValue)); + } + } + } + } + } + + return exportModels; + } + + private static void WriteModel(ITemplateModel template, string outputPath) + { + if (template != null) + { + var result = template.RenderModel(); + if (result != null && template.Id != null) + { + var resultPath = template.Id.Replace('.', '\\'); + resultPath = Path.Combine(outputPath, resultPath); + resultPath = $"{resultPath}.g.cs"; + + var resultDirectory = Path.GetDirectoryName(resultPath); + if (!Directory.Exists(resultDirectory)) Directory.CreateDirectory(resultDirectory); + + File.WriteAllText(resultPath, result); + } + } + } + + private static void WriteInterface(ITemplateModel template, string outputPath) + { + if (template != null) + { + var result = template.RenderInterface(); + if (result != null && template.Id != null) + { + var resultPath = template.Id.Replace('.', '\\'); + resultPath = Path.Combine(outputPath, resultPath); + var resultDirectory = Path.GetDirectoryName(resultPath); + var resultFilename = Path.GetFileName(resultPath); + resultPath = Path.Combine(resultDirectory, $"I{resultFilename}.g.cs"); + + if (!Directory.Exists(resultDirectory)) Directory.CreateDirectory(resultDirectory); + + File.WriteAllText(resultPath, result); + } + } + } + } +} diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Assets.CuttingToolMeasurement.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Assets.CuttingToolMeasurement.scriban new file mode 100644 index 00000000..a2dabfa4 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Assets.CuttingToolMeasurement.scriban @@ -0,0 +1,37 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace MTConnect.Assets.CuttingTools.Measurements +{ + /// + /// {{description}} + /// + public class {{name}} : Measurement + { + public const string TypeId = "{{type_id}}"; + public const string CodeId = "{{code_id}}"; + + + public {{name}}() + { + Type = TypeId; + Code = CodeId; + {{ if (units_enum) }}Units = {{units_enum}};{{ end }} + } + + public {{name}}(double value) + { + Type = TypeId; + Code = CodeId; + Value = value; + {{ if (units_enum) }}Units = {{units_enum}};{{ end }} + } + + public {{name}}(Measurement measurement) : base(measurement) + { + Type = TypeId; + Code = CodeId; + {{ if (units_enum) }}Units = {{units_enum}};{{ end }} + } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Devices.ComponentType.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.ComponentType.scriban new file mode 100644 index 00000000..67650f19 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.ComponentType.scriban @@ -0,0 +1,24 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +// MTConnect SysML v2.2 : UML ID = {{uml_id}} + +namespace MTConnect.Devices.Components +{ + /// + /// {{description}} + /// + public {{- if (is_abstract) }} abstract{{ end }} class {{name}}Component : {{ if (parent_type) }}{{parent_type}}{{else}}Component{{ end }} {{- if (is_organizer) }}, IOrganizerComponent{{ end }} + { + public const string TypeId = "{{type}}"; + public const string NameId = "{{default_name}}"; + public new const string DescriptionText = "{{description}}"; + + public override string TypeDescription => DescriptionText; + {{ if (maximum_version_enum) }}public override System.Version MaximumVersion => {{maximum_version_enum}};{{ end }} + {{ if (minimum_version_enum) }}public override System.Version MinimumVersion => {{minimum_version_enum}};{{ end }} + + + public {{name}}Component() { Type = TypeId; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Devices.CompositionType.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.CompositionType.scriban new file mode 100644 index 00000000..b3c0d3a5 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.CompositionType.scriban @@ -0,0 +1,22 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace MTConnect.Devices.Compositions +{ + /// + /// {{description}} + /// + public class {{name}}Composition : {{ if (parent_type) }}{{parent_type}}{{else}}Composition{{ end }} + { + public const string TypeId = "{{type}}"; + public const string NameId = "{{default_name}}"; + public new const string DescriptionText = "{{description}}"; + + public override string TypeDescription => DescriptionText; + {{ if (maximum_version_enum) }}public override System.Version MaximumVersion => {{maximum_version_enum}};{{ end }} + {{ if (minimum_version_enum) }}public override System.Version MinimumVersion => {{minimum_version_enum}};{{ end }} + + + public {{name}}Composition() { Type = TypeId; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Devices.DataItemType.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.DataItemType.scriban new file mode 100644 index 00000000..e2a61ced --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.DataItemType.scriban @@ -0,0 +1,90 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace MTConnect.Devices.DataItems +{ + /// + /// {{description}} + /// + public class {{name}} : DataItem + { + public const DataItemCategory CategoryId = DataItemCategory.{{category}}; + public const string TypeId = "{{type}}"; + public const string NameId = "{{default_name}}"; + {{ if (units_enum) }}public const string DefaultUnits = {{units_enum}};{{ end }} + public new const string DescriptionText = "{{description}}"; + + public override string TypeDescription => DescriptionText; + {{ if (maximum_version_enum) }}public override System.Version MaximumVersion => {{maximum_version_enum}};{{ end }} + {{ if (minimum_version_enum) }}public override System.Version MinimumVersion => {{minimum_version_enum}};{{ end }} + +{{ if ((sub_types | array.size) > 0) }}{{ i = 0 }} + public enum SubTypes + { +{{- for sub_type in sub_types }}{{ i = i + 1 }} + /// + /// {{sub_type.description}} + /// + {{sub_type.name}} + {{- if (i < (sub_types | array.size)) }}, + {{ end }} +{{- end }} + } + +{{ end }} + public {{name}}() + { + Category = CategoryId; + Type = TypeId; + {{ if (units_enum) }}Units = DefaultUnits;{{ end }} + } + +{{- if ((sub_types | array.size) > 0) }} + + public {{name}}( + string parentId, + SubTypes subType + ) + { + Id = CreateId(parentId, NameId, GetSubTypeId(subType)); + Category = CategoryId; + Type = TypeId; + SubType = subType.ToString(); + Name = NameId; + {{ if (units_enum) }}Units = DefaultUnits;{{ end }} + } + + public override string SubTypeDescription => GetSubTypeDescription(SubType); + +{{- if ((sub_types | array.size) > 0) }}{{ i = 0 }} + + public static string GetSubTypeDescription(string subType) + { + var s = subType.ConvertEnum(); + switch (s) + { +{{- for sub_type in sub_types }}{{ i = i + 1 }} + case SubTypes.{{sub_type.name}}: return "{{sub_type.description}}"; +{{- end }} + } + + return null; + } +{{- end }} +{{- if ((sub_types | array.size) > 0) }}{{ i = 0 }} + + public static string GetSubTypeId(string subType) + { + switch (subType) + { +{{- for sub_type in sub_types }}{{ i = i + 1 }} + case SubTypes.{{sub_type.name}}: return "{{sub_type.name}}"; +{{- end }} + } + + return null; + } +{{- end }} +{{- end }} + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Devices.Device.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.Device.scriban new file mode 100644 index 00000000..d8756883 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Devices.Device.scriban @@ -0,0 +1,736 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using MTConnect.Devices.Configurations; +using MTConnect.Devices.DataItems; +using MTConnect.Devices.References; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.Devices +{ + /// + /// {{descriptions.devices_device}} + /// + public class Device : IDevice + { + public const string TypeId = "Device"; + public const string DescriptionText = "{{descriptions.devices_device}}"; + + private static readonly Version DefaultMaximumVersion = null; + private static readonly Version DefaultMinimumVersion = MTConnectVersions.Version10; + + + /// + /// {{descriptions.devices_component_id}} + /// + public string Id { get; set; } + + /// + /// {{descriptions.devices_device_name}} + /// + public string Name { get; set; } + + /// + /// {{descriptions.devices_device_uuid}} + /// + public string Uuid { get; set; } + + /// + /// The type of Device + /// + public string Type { get; set; } + + /// + /// {{descriptions.devices_device_iso841class}} + /// + public string Iso841Class { get; set; } + + /// + /// {{descriptions.devices_component_nativename}} + /// + public string NativeName { get; set; } + + /// + /// {{descriptions.devices_component_sampleinterval}} + /// + public double SampleInterval { get; set; } + + /// + /// {{descriptions.devices_component_samplerate}} + /// + public double SampleRate { get; set; } + + /// + /// {{descriptions.devices_component_coordinatesystemidref}} + /// + public string CoordinateSystemIdRef { get; set; } + + /// + /// {{descriptions.devices_device_mtconnectversion}} + /// + public virtual Version MTConnectVersion { get; set; } + + /// + /// {{descriptions.devices_device_hash}} + /// + public string Hash { get; set; } + + /// + /// Descriptive content. + /// + public virtual IDescription Description { get; set; } + + /// + /// An XML element that contains technical information about a piece of equipment describing its physical layout or functional characteristics. + /// + public IConfiguration Configuration { get; set; } + + /// + /// A container for the Data XML Elements provided by this Device. + /// The data items define the measured values to be reported by this Device. + /// + public virtual IEnumerable DataItems { get; set; } + + /// + /// A container for SubComponent XML Elements. + /// + public virtual IEnumerable Components { get; set; } + + /// + /// A container for the Composition elements associated with this Device element. + /// + public virtual IEnumerable Compositions { get; set; } + + /// + /// An XML container consisting of one or more types of Reference XML elements. + /// + public IEnumerable References { get; set; } + + /// + /// The Agent InstanceId that produced this Device + /// + public long InstanceId { get; set; } + + + /// + /// The Container that this Device is directly associated with + /// + public IContainer Parent { get; set; } + + + /// + /// The text description that describes what the Device Type represents + /// + public virtual string TypeDescription => DescriptionText; + + /// + /// Gets whether the Device is an Organizer Type + /// + public bool IsOrganizer => false; + + + /// + /// The full path of IDs that describes the location of the Device in the Device + /// + public string IdPath => Id; + + /// + /// The list of IDs (in order) that describes the location of the Device in the Device + /// + public string[] IdPaths => new string[] { Id }; + + /// + /// The full path of Types that describes the location of the Device in the Device + /// + public string TypePath => Type; + + /// + /// The list of Types (in order) that describes the location of the Device in the Device + /// + public string[] TypePaths => new string[] { Type }; + + + /// + /// The maximum MTConnect Version that this Device Type is valid + /// (if set, this indicates that the Type has been Deprecated in the MTConnect Standard version specified) + /// + public virtual Version MaximumVersion => DefaultMaximumVersion; + + /// + /// The minimum MTConnect Version that this Device Type is valid + /// + public virtual Version MinimumVersion => DefaultMinimumVersion; + + + public Device() + { + Id = StringFunctions.RandomString(10); + Name = "dev"; + Uuid = Guid.NewGuid().ToString(); + Type = TypeId; + DataItems = new List(); + Components = new List(); + Compositions = new List(); + } + + + public string GenerateHash() + { + return GenerateHash(this); + } + + public static string GenerateHash(IDevice device) + { + if (device != null) + { + var ids = new List(); + + var hashMembers = new string[10]; + hashMembers[0] = $"uuid:{device.Uuid}"; + hashMembers[1] = $"id:{device.Id}"; + hashMembers[2] = $"name:{device.Name}"; + hashMembers[3] = $"type:{device.Type}"; + hashMembers[4] = $"nativeName:{device.NativeName}"; + hashMembers[5] = $"sampleInterval:{device.SampleInterval}"; + hashMembers[6] = $"sampleRate:{device.SampleRate}"; + hashMembers[7] = $"coordinateSystemIdRef:{device.CoordinateSystemIdRef}"; + hashMembers[8] = $"iso841Class:{device.Iso841Class}"; + hashMembers[9] = $"mtconnectVersion:{device.MTConnectVersion}"; + var propertiesHash = string.Join(";", hashMembers).ToSHA1Hash(); + ids.Add(propertiesHash); + + // Add DataItem Change Ids + if (!device.DataItems.IsNullOrEmpty()) + { + foreach (var dataItem in device.DataItems) + { + ids.Add(dataItem.Hash); + } + } + + // Add Composition Change Ids + if (!device.Compositions.IsNullOrEmpty()) + { + foreach (var composition in device.Compositions) + { + ids.Add(composition.Hash); + } + } + + // Add Component Change Ids + if (!device.Components.IsNullOrEmpty()) + { + foreach (var component in device.Components) + { + ids.Add(component.Hash); + } + } + + return StringFunctions.ToSHA1Hash(ids.ToArray()); + } + + return null; + } + + //public static string CreateDeviceHash(IDevice device) + //{ + // var s = ObjectExtensions.GetHashPropertyString(device); + // return s.ToMD5Hash(); + //} + + + #region "Components" + + /// + /// Return a list of All Components + /// + public IEnumerable GetComponents() + { + return GetComponents(this); + } + + private static List GetComponents(IDevice device) + { + var l = new List(); + + if (device != null && !device.Components.IsNullOrEmpty()) + { + foreach (var subComponent in device.Components) + { + var components = GetComponents(subComponent); + if (components != null && components.Count > 0) l.AddRange(components); + } + } + return l.Count > 0 ? l : null; + } + + private static List GetComponents(IComponent component) + { + var l = new List(); + l.Add(component); + + if (!component.Components.IsNullOrEmpty()) + { + foreach (var subComponent in component.Components) + { + var components = GetComponents(subComponent); + if (components != null && components.Count > 0) l.AddRange(components); + } + } + return l.Count > 0 ? l : null; + } + + + /// + /// Add a Component to the Device + /// + /// The Component to add + public void AddComponent(IComponent component) + { + if (component != null) + { + var components = new List(); + + if (!Components.IsNullOrEmpty()) + { + components.AddRange(Components); + } + + var organizerType = Organizers.GetOrganizerType(component.Type); + if (organizerType != null) + { + if (!components.Any(o => o.Type == organizerType)) + { + var organizer = Component.Create(organizerType); + if (organizer != null) + { + organizer.AddComponent(component); + components.Add(organizer); + } + } + } + else + { + components.Add(component); + } + + Components = components; + } + } + + /// + /// Add Components to the Device + /// + /// The Components to add + public void AddComponents(IEnumerable components) + { + if (!components.IsNullOrEmpty()) + { + var newComponents = new List(); + + if (!Components.IsNullOrEmpty()) + { + newComponents.AddRange(Components); + } + + newComponents.AddRange(components); + Components = newComponents; + } + } + + + /// + /// Remove a Component from the Device + /// + /// The ID of the Component to remove + public void RemoveComponent(string componentId) + { + if (!Components.IsNullOrEmpty()) + { + var components = new List(); + components.AddRange(Components); + + components.RemoveAll(o => o.Id == componentId); + + foreach (var subComponent in components) + { + RemoveComponent(subComponent, componentId); + } + + Components = components; + } + } + + private void RemoveComponent(IComponent component, string componentId) + { + if (component != null && !component.Components.IsNullOrEmpty()) + { + var components = new List(); + components.AddRange(component.Components); + components.RemoveAll(o => o.Id == componentId); + + foreach (var subComponent in components) + { + RemoveComponent(subComponent, componentId); + } + + component.Components = components; + } + } + + #endregion + + #region "Compositions" + + /// + /// Return a list of All Compositions + /// + public IEnumerable GetCompositions() + { + var l = new List(); + + var components = GetComponents(); + if (!components.IsNullOrEmpty()) + { + foreach (var component in components) + { + if (!component.Compositions.IsNullOrEmpty()) + { + l.AddRange(component.Compositions); + } + } + } + + return !l.IsNullOrEmpty() ? l : null; + } + + + /// + /// Add a Composition to the Device + /// + /// The Composition to add + public void AddComposition(IComposition composition) + { + if (composition != null) + { + var compositions = new List(); + + if (!Compositions.IsNullOrEmpty()) + { + compositions.AddRange(Compositions); + } + + compositions.Add(composition); + Compositions = compositions; + } + } + + /// + /// Add Compositions to the Device + /// + /// The Compositions to add + public void AddCompositions(IEnumerable compositions) + { + if (!compositions.IsNullOrEmpty()) + { + var newCompositions = new List(); + + if (!Compositions.IsNullOrEmpty()) + { + newCompositions.AddRange(Compositions); + } + + newCompositions.AddRange(compositions); + Compositions = newCompositions; + } + } + + + /// + /// Remove a Composition from the Device + /// + /// The ID of the Composition to remove + public void RemoveComposition(string compositionId) + { + var components = GetComponents(); + if (!components.IsNullOrEmpty()) + { + foreach (var component in components) + { + if (!component.Compositions.IsNullOrEmpty()) + { + var compositions = new List(); + compositions.AddRange(component.Compositions); + compositions.RemoveAll(o => o.Id == compositionId); + component.Compositions = compositions; + } + } + } + } + + #endregion + + #region "DataItems" + + /// + /// Return a list of All DataItems + /// + public IEnumerable GetDataItems() + { + var l = new List(); + + // Add Root DataItems + if (!DataItems.IsNullOrEmpty()) l.AddRange(DataItems); + + // Add Composition DataItems + if (!Compositions.IsNullOrEmpty()) + { + foreach (var composition in Compositions) + { + if (!composition.DataItems.IsNullOrEmpty()) l.AddRange(composition.DataItems); + } + } + + // Add Component DataItems + if (!Components.IsNullOrEmpty()) + { + foreach (var component in Components) + { + var componentDataItems = GetDataItems(component); + if (!componentDataItems.IsNullOrEmpty()) l.AddRange(componentDataItems); + } + } + + return !l.IsNullOrEmpty() ? l : null; + } + + private static IEnumerable GetDataItems(IComponent component) + { + var l = new List(); + + // Add Root DataItems + if (!component.DataItems.IsNullOrEmpty()) l.AddRange(component.DataItems); + + // Add Composition DataItems + if (!component.Compositions.IsNullOrEmpty()) + { + foreach (var composition in component.Compositions) + { + if (!composition.DataItems.IsNullOrEmpty()) l.AddRange(composition.DataItems); + } + } + + // Add SubComponent DataItems + if (!component.Components.IsNullOrEmpty()) + { + // Get SubComponent DataItems + foreach (var subComponent in component.Components) + { + var componentDataItems = GetDataItems(subComponent); + if (!componentDataItems.IsNullOrEmpty()) l.AddRange(componentDataItems); + } + } + + return !l.IsNullOrEmpty() ? l : null; + } + + /// + /// Return the DataItem matching either the ID, Name, or Source of the specified Key + /// + public IDataItem GetDataItemByKey(string dataItemKey) + { + if (!string.IsNullOrEmpty(dataItemKey)) + { + var dataItems = GetDataItems(); + if (!dataItems.IsNullOrEmpty()) + { + // Check DataItem ID + var dataItem = dataItems.FirstOrDefault(o => o.Id == dataItemKey); + + // Check DataItem Name + if (dataItem == null) dataItem = dataItems.FirstOrDefault(o => o.Name == dataItemKey); + + // Check DataItem Source DataItemId + if (dataItem == null) dataItem = dataItems.FirstOrDefault(o => o.Source != null && o.Source.DataItemId == dataItemKey); + + // Check DataItem Source Value + if (dataItem == null) dataItem = dataItems.FirstOrDefault(o => o.Source != null && o.Source.Value == dataItemKey); + + // Return DataItem + return dataItem; + } + } + + return null; + } + + + /// + /// Add a DataItem to the Device + /// + /// The DataItem to add + public void AddDataItem(IDataItem dataItem) + { + if (dataItem != null) + { + var dataItems = new List(); + + if (!DataItems.IsNullOrEmpty()) + { + dataItems.AddRange(DataItems); + } + + dataItems.Add(dataItem); + DataItems = dataItems; + } + } + + public void AddDataItem(DataItemCategory category, string type, string subType = null, string dataItemId = null) + { + if (!string.IsNullOrEmpty(type)) + { + AddDataItem(new DataItem(category, type, subType, dataItemId)); + } + } + + /// + /// Add DataItems to the Device + /// + /// The DataItems to add + public void AddDataItems(IEnumerable dataItems) + { + if (!dataItems.IsNullOrEmpty()) + { + var newDataItems = new List(); + + if (!DataItems.IsNullOrEmpty()) + { + newDataItems.AddRange(DataItems); + } + + newDataItems.AddRange(dataItems); + DataItems = newDataItems; + } + } + + + /// + /// Remove a DataItem from the Device + /// + /// The ID of the DataItem to remove + public void RemoveDataItem(string dataItemId) + { + var components = GetComponents(); + if (!components.IsNullOrEmpty()) + { + foreach (var component in components) + { + if (!component.DataItems.IsNullOrEmpty()) + { + var dataItems = new List(); + dataItems.AddRange(component.DataItems); + dataItems.RemoveAll(o => o.Id == dataItemId); + component.DataItems = dataItems; + } + } + } + } + + #endregion + + + public static Device Process(IDevice device, Version mtconnectVersion) + { + if (device != null) + { + Device obj = null; + + if (device.Type == TypeId) obj = new Device(); + else if (device.Type == Agent.TypeId) obj = new Agent(); + + // Don't Ouput Agent Device if Version < 1.7 + if (device.Type == Agent.TypeId && mtconnectVersion < MTConnectVersions.Version17) return null; + + if (obj != null) + { + obj.Id = device.Id; + obj.Name = device.Name; + obj.NativeName = device.NativeName; + obj.Uuid = device.Uuid; + obj.InstanceId = device.InstanceId; + obj.Type = device.Type; + obj.Parent = device; + + // Set Device Description + if (device.Description != null) + { + var description = new Description(); + description.Manufacturer = device.Description.Manufacturer; + if (mtconnectVersion >= MTConnectVersions.Version12) description.Model = device.Description.Model; + description.SerialNumber = device.Description.SerialNumber; + description.Station = device.Description.Station; + description.Value = device.Description.Value; + obj.Description = description; + } + + if (mtconnectVersion < MTConnectVersions.Version12) obj.Iso841Class = device.Iso841Class; + if (mtconnectVersion < MTConnectVersions.Version12) obj.SampleRate = device.SampleRate; + if (mtconnectVersion >= MTConnectVersions.Version12) obj.SampleInterval = device.SampleInterval; + if (mtconnectVersion >= MTConnectVersions.Version13) obj.References = device.References; + if (mtconnectVersion >= MTConnectVersions.Version17) obj.Configuration = device.Configuration; + if (mtconnectVersion >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = device.CoordinateSystemIdRef; + if (mtconnectVersion >= MTConnectVersions.Version17) obj.MTConnectVersion = device.MTConnectVersion != null ? device.MTConnectVersion : mtconnectVersion; + if (mtconnectVersion >= MTConnectVersions.Version22) obj.Hash = device.Hash; + + // Add DataItems + if (!device.DataItems.IsNullOrEmpty()) + { + var dataItems = new List(); + + foreach (var dataItem in device.DataItems) + { + var dataItemObj = DataItem.Process(dataItem, mtconnectVersion); + if (dataItemObj != null) dataItems.Add(dataItemObj); + } + + obj.DataItems = dataItems; + } + + // Add Compositions + if (!device.Compositions.IsNullOrEmpty()) + { + var compositions = new List(); + + foreach (var composition in device.Compositions) + { + var compositionObj = Composition.Process(composition, mtconnectVersion); + if (compositionObj != null) compositions.Add(compositionObj); + } + + obj.Compositions = compositions; + } + + // Add Components + if (!device.Components.IsNullOrEmpty()) + { + var components = new List(); + + foreach (var component in device.Components) + { + var componentObj = Component.Process(component, mtconnectVersion); + if (componentObj != null) components.Add(componentObj); + } + + obj.Components = components; + } + + return obj; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Enum.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Enum.scriban new file mode 100644 index 00000000..61bd89ec --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Enum.scriban @@ -0,0 +1,17 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace {{namespace}} +{ + public enum {{name}} + { +{{- i = 0 }}{{ for value in values }}{{ i = i + 1 }} + /// + /// {{value.description}} + /// + {{value.name}} + {{- if (i < (values | array.size)) }}, + {{ end }} +{{- end }} + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/EnumString.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/EnumString.scriban new file mode 100644 index 00000000..0749d31b --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/EnumString.scriban @@ -0,0 +1,17 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace {{namespace}} +{ + public static class {{name}} + { +{{- i = 0 }}{{ for value in values }}{{ i = i + 1 }} + /// + /// {{value.description}} + /// + public const string {{value.name}} = "{{value.name}}"; + {{- if (i < (values | array.size)) }} + {{ end }} +{{- end }} + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Interface.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Interface.scriban new file mode 100644 index 00000000..21f8b2e3 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Interface.scriban @@ -0,0 +1,21 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace {{namespace}} +{ + /// + /// {{description}} + /// + public interface I{{name}} {{- if (parent_type) }} : I{{parent_type}}{{ end }} + { +{{- i = 0 }}{{- for property in properties }}{{ i = i + 1 }} + /// + /// {{property.description}} + /// + {{ if (property.is_array) }}IEnumerable<{{property.data_type}}> {{property.name}} { get; }{{ end }} + {{- if (!property.is_array) }}{{property.data_type}} {{property.name}} { get; }{{ end }} + {{- if (i < (properties | array.size)) }} + {{ end }} +{{- end }} + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Model.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Model.scriban new file mode 100644 index 00000000..88c1a8ef --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Model.scriban @@ -0,0 +1,25 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +// MTConnect SysML v2.2 : UML ID = {{uml_id}} + +namespace {{namespace}} +{ + /// + /// {{description}} + /// + public {{- if (is_partial) }} partial{{ end }} {{- if (is_abstract) }} abstract{{ end }} class {{name}} : {{ if (parent_type) }}{{parent_type}}, I{{name}}{{else}}I{{name}}{{ end }} + { + public const string DescriptionText = "{{description}}"; + +{{ i = 0 }}{{- for property in properties }}{{ i = i + 1 }} + /// + /// {{property.description}} + /// + {{ if (property.is_array) }}public IEnumerable<{{property.data_type}}> {{property.name}} { get; set; }{{ end }} + {{- if (!property.is_array) }}public {{property.data_type}} {{property.name}} { get; set; }{{ end }} + {{- if (i < (properties | array.size)) }} + {{ end }} +{{- end }} + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/Templates/Observations.Observation.scriban b/src/MTConnect.NET-SysML/CSharp/Templates/Observations.Observation.scriban new file mode 100644 index 00000000..2814ee91 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/Templates/Observations.Observation.scriban @@ -0,0 +1,20 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace {{namespace}} +{ + /// + /// {{description}} + /// + public enum {{name}} + { +{{- i = 0 }}{{ for value in values }}{{ i = i + 1 }} + /// + /// {{value.description}} + /// + {{value.name}} + {{- if (i < (values | array.size)) }}, + {{ end }} +{{- end }} + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/CSharp/UnitsHelper.cs b/src/MTConnect.NET-SysML/CSharp/UnitsHelper.cs new file mode 100644 index 00000000..66e9e618 --- /dev/null +++ b/src/MTConnect.NET-SysML/CSharp/UnitsHelper.cs @@ -0,0 +1,17 @@ +namespace MTConnect.SysML.CSharp +{ + internal static class UnitsHelper + { + public static string Get(string units) + { + if (units != null) + { + units = units.Replace("/", "_PER_"); + units = units.Replace("^2", "_SQUARED"); + //if (units.EndsWith("^3")) units = units.Replace("^3", "_CUBED"); + } + + return units; + } + } +} diff --git a/src/MTConnect.NET-SysML/Extensions/ListExtensions.cs b/src/MTConnect.NET-SysML/Extensions/ListExtensions.cs new file mode 100644 index 00000000..cb9eeef4 --- /dev/null +++ b/src/MTConnect.NET-SysML/Extensions/ListExtensions.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML +{ + internal static class ListExtensions + { + /// + /// Determines whether the collection is null or contains no elements. + /// + /// The IEnumerable type. + /// The enumerable, which may be null or empty. + /// + /// true if the IEnumerable is null or empty; otherwise, false. + /// + public static bool IsNullOrEmpty(this IEnumerable enumerable) + { + if (enumerable == null) + { + return true; + } + + /* If this is a list, use the Count property for efficiency. + * The Count property is O(1) while IEnumerable.Count() is O(N). */ + var collection = enumerable as ICollection; + if (collection != null) + { + return collection.Count < 1; + } + + var a = enumerable as Array; + if (a != null) + { + return a.Length < 1; + } + + return !enumerable.Any(); + } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Extensions/StringFunctions.cs b/src/MTConnect.NET-SysML/Extensions/StringFunctions.cs new file mode 100644 index 00000000..e38e86ec --- /dev/null +++ b/src/MTConnect.NET-SysML/Extensions/StringFunctions.cs @@ -0,0 +1,576 @@ +// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace MTConnect.SysML +{ + internal static class StringFunctions + { + private static readonly Encoding _utf8 = Encoding.UTF8; + + [ThreadStatic] + private static MD5 _md5; + + [ThreadStatic] + private static SHA1 _sha1; + + [ThreadStatic] + private static Random _random; + + private static MD5 MD5Algorithm + { + get + { + if (_md5 == null) + { + _md5 = MD5.Create(); + } + return _md5; + } + } + + private static SHA1 SHA1Algorithm + { + get + { + if (_sha1 == null) + { + _sha1 = SHA1.Create(); + } + return _sha1; + } + } + + private static Random Random + { + get + { + if (_random == null) + { + _random = new Random(); + } + + return _random; + } + } + + public static string ToPascalCase(this string s) + { + if (!string.IsNullOrEmpty(s)) + { + var parts = s.SplitOnWord(); + if (!parts.IsNullOrEmpty()) + { + var sb = new StringBuilder(); + for (var i = 0; i <= parts.Count() - 1; i++) + { + sb.Append(parts[i].UppercaseFirstCharacter()); + } + return sb.ToString(); + } + } + + return null; + } + + public static string ToTitleCase(this string s) + { + if (!string.IsNullOrEmpty(s)) + { + var parts = s.SplitOnWord(); + if (!parts.IsNullOrEmpty()) + { + var sb = new StringBuilder(); + for (var i = 0; i <= parts.Count() - 1; i++) + { + sb.Append(parts[i].UppercaseFirstCharacter()); + } + return sb.ToString(); + } + } + + return null; + } + + public static string ToCamelCase(this string s) + { + if (!string.IsNullOrEmpty(s)) + { + var parts = s.SplitOnWord(); + if (!parts.IsNullOrEmpty()) + { + var sb = new StringBuilder(); + for (var i = 0; i <= parts.Count() - 1; i++) + { + if (i > 0) sb.Append(parts[i].UppercaseFirstCharacter()); + else sb.Append(parts[i].ToLower()); + } + return sb.ToString(); + } + } + + return null; + } + + public static string[] SplitOnWord(this string s) + { + if (!string.IsNullOrEmpty(s)) + { + string[] parts; + + if (s.Contains(' ')) + { + // Split string by empty space + parts = s.Split(' '); + } + else if (s.Contains('_')) + { + // Split string by underscore + parts = s.Split('_'); + } + else + { + // Split string by Uppercase characters + parts = SplitOnUppercase(s); + } + + return parts; + } + + return new string[] { s }; + } + + public static string[] SplitOnUppercase(this string s) + { + if (!string.IsNullOrEmpty(s)) + { + if (s != s.ToUpper()) + { + var p = ""; + var x = 0; + for (var i = 0; i < s.Length; i++) + { + if (i > 0 && char.IsUpper(s[i])) + { + p += s.Substring(x, i - x) + " "; + x = i; + } + + if (i == s.Length - 1) + { + p += s.Substring(x); + } + } + return p.Split(' '); + } + else return new string[] { s }; + } + + return null; + } + + public static string UppercaseFirstCharacter(this string s) + { + if (s == null) return null; + + if (s.Length > 1) + { + var l = s.ToLower().ToCharArray(); + var a = new char[l.Length]; + + a[0] = char.ToUpper(l[0]); + Array.Copy(l, 1, a, 1, a.Length - 1); + + return new string(a); + } + + return s.ToUpper(); + } + + public static string LowercaseFirstCharacter(this string s) + { + if (s == null) return null; + + if (s.Length > 1) + { + var l = s.ToCharArray(); + var a = new char[l.Length]; + + a[0] = char.ToLower(l[0]); + Array.Copy(l, 1, a, 1, a.Length - 1); + + return new string(a); + } + + return s.ToLower(); + } + + + public static string ToUnderscore(this string s, bool splitOnUppercase = true) + { + if (!string.IsNullOrEmpty(s)) + { + if (s != s.ToUpper()) + { + string[] parts = null; + + if (s.Contains(' ')) + { + parts = s.Split(' '); + } + else if (splitOnUppercase) + { + // Split string by Uppercase characters + parts = Regex.Split(s, @"(?(); + if (!parts.IsNullOrEmpty()) foreach (var part in parts) a.Add(part.Trim()); + if (!a.IsNullOrEmpty()) + { + string x = string.Join("_", a); + return x.ToLower(); + } + } + else return s.ToLower(); + } + + return null; + } + + public static string ToUnderscoreUpper(this string s, bool splitOnUppercase = true) + { + if (!string.IsNullOrEmpty(s)) + { + if (s != s.ToUpper()) + { + string[] parts = null; + + if (s.Contains(' ')) + { + parts = s.Split(' '); + } + else if (splitOnUppercase) + { + // Split string by Uppercase characters + parts = Regex.Split(s, @"(?(); + if (!parts.IsNullOrEmpty()) foreach (var part in parts) a.Add(part.Trim()); + if (!a.IsNullOrEmpty()) + { + string x = string.Join("_", a); + return x.ToUpper(); + } + } + else return s.ToUpper(); + } + + return null; + } + + public static string RandomString(int length) + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[Random.Next(s.Length)]).ToArray()); + } + + public static DateTime ToDateTime(this string s) + { + if (DateTime.TryParse(s, out var dateTime)) + { + return dateTime; + } + + return DateTime.MinValue; + } + + public static string ToMD5Hash(this string s) + { + try + { + var hash = MD5Algorithm.ComputeHash(_utf8.GetBytes(s)); + return string.Concat(hash.Select(b => b.ToString("x2"))); + } + catch { } + + return null; + } + + public static string ToMD5Hash(this byte[] bytes) + { + if (bytes != null) + { + try + { + var hash = MD5Algorithm.ComputeHash(bytes); + return string.Concat(hash.Select(b => b.ToString("x2"))); + } + catch { } + } + + return null; + } + + public static string ToMD5HashString(this byte[] hashBytes) + { + if (hashBytes != null) + { + try + { + return string.Concat(hashBytes.Select(b => b.ToString("x2"))); + } + catch { } + } + + return null; + } + + public static byte[] ToMD5HashBytes(this string s) + { + try + { + return MD5Algorithm.ComputeHash(_utf8.GetBytes(s)); + } + catch { } + + return null; + } + + public static byte[] ToMD5HashBytes(this byte[] bytes) + { + if (bytes != null) + { + try + { + return MD5Algorithm.ComputeHash(bytes); + } + catch { } + } + return null; + } + + public static string ToMD5Hash(string[] lines) + { + if (lines != null && lines.Length > 0) + { + var x1 = lines[0]; + var h = x1.ToMD5Hash(); + + for (int i = 1; i < lines.Length; i++) + { + x1 = lines[i].ToMD5Hash(); + x1 = h + x1; + h = x1.ToMD5Hash(); + } + + return h; + } + + return null; + } + + public static byte[] ToMD5HashBytes(byte[][] hashBytes) + { + if (hashBytes != null && hashBytes.Length > 0) + { + var x1 = hashBytes[0]; + var x2 = x1; + byte[] a1; + + for (int i = 1; i < hashBytes.Length; i++) + { + x2 = hashBytes[i]; + if (x2 != null) + { + a1 = new byte[x1.Length + x2.Length]; + Array.Copy(x1, 0, a1, 0, x1.Length); + Array.Copy(x2, 0, a1, x1.Length, x2.Length); + + x1 = a1.ToMD5HashBytes(); + } + } + + return x2; + } + + return null; + } + + + public static string ToSHA1Hash(this string s) + { + try + { + var hash = SHA1Algorithm.ComputeHash(_utf8.GetBytes(s)); + return string.Concat(hash.Select(b => b.ToString("x2"))); + } + catch { } + + return null; + } + + public static string ToSHA1Hash(this byte[] bytes) + { + if (bytes != null) + { + try + { + var hash = SHA1Algorithm.ComputeHash(bytes); + return string.Concat(hash.Select(b => b.ToString("x2"))); + } + catch { } + } + + return null; + } + + public static string ToSHA1HashString(this byte[] hashBytes) + { + if (hashBytes != null) + { + try + { + return string.Concat(hashBytes.Select(b => b.ToString("x2"))); + } + catch { } + } + + return null; + } + + public static byte[] ToSHA1HashBytes(this string s) + { + try + { + return SHA1Algorithm.ComputeHash(_utf8.GetBytes(s)); + } + catch { } + + return null; + } + + public static byte[] ToSHA1HashBytes(this byte[] bytes) + { + if (bytes != null) + { + try + { + return SHA1Algorithm.ComputeHash(bytes); + } + catch { } + } + return null; + } + + public static string ToSHA1Hash(string[] lines) + { + if (lines != null && lines.Length > 0) + { + var x1 = lines[0]; + var h = x1.ToSHA1Hash(); + + for (int i = 1; i < lines.Length; i++) + { + x1 = lines[i].ToSHA1Hash(); + x1 = h + x1; + h = x1.ToSHA1Hash(); + } + + return h; + } + + return null; + } + + public static byte[] ToSHA1HashBytes(byte[][] hashBytes) + { + if (hashBytes != null && hashBytes.Length > 0) + { + var x1 = hashBytes[0]; + var x2 = x1; + byte[] a1; + + for (int i = 1; i < hashBytes.Length; i++) + { + x2 = hashBytes[i]; + if (x2 != null) + { + a1 = new byte[x1.Length + x2.Length]; + Array.Copy(x1, 0, a1, 0, x1.Length); + Array.Copy(x2, 0, a1, x1.Length, x2.Length); + + x1 = a1.ToSHA1HashBytes(); + } + } + + return x2; + } + + return null; + } + + + public static string ToFileSize(this long byteCount) + { + string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB + if (byteCount == 0) + return "0" + suf[0]; + long bytes = Math.Abs(byteCount); + int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); + double num = Math.Round(bytes / Math.Pow(1024, place), 1); + return (Math.Sign(byteCount) * num).ToString() + suf[place]; + } + + public static string ToFileSize(this decimal byteCount) + { + var x = (long)byteCount; + return x.ToFileSize(); + } + + + public static bool IsHtml(this string s) + { + if (!string.IsNullOrEmpty(s)) + { + var regex = new Regex(@"<\s*([^ >]+)[^>]*>.*?<\s*/\s*\1\s*>"); + return regex.IsMatch(s); + } + + return false; + } + + public static T ConvertEnum(this string value) where T : struct + { + if (value != null && typeof(T).IsEnum) + { + if (Enum.TryParse(value.ToString(), true, out var result)) + { + return (T)result; + } + } + + return default; + } + + public static ulong GetUInt64Hash(this string text) + { + using (var md5 = MD5.Create()) + { + var bytes = md5.ComputeHash(Encoding.Default.GetBytes(text)); + Array.Resize(ref bytes, bytes.Length + bytes.Length % 8); //make multiple of 8 if hash is not, for exampel SHA1 creates 20 bytes. + return Enumerable.Range(0, bytes.Length / 8) // create a counter for de number of 8 bytes in the bytearray + .Select(i => BitConverter.ToUInt64(bytes, i * 8)) // combine 8 bytes at a time into a integer + .Aggregate((x, y) => x ^ y); //xor the bytes together so you end up with a ulong (64-bit int) + } + } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/IMTConnectExportModel.cs b/src/MTConnect.NET-SysML/IMTConnectExportModel.cs new file mode 100644 index 00000000..397d8beb --- /dev/null +++ b/src/MTConnect.NET-SysML/IMTConnectExportModel.cs @@ -0,0 +1,9 @@ +namespace MTConnect.SysML +{ + public interface IMTConnectExportModel + { + string UmlId { get; } + + string Id { get; } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnect.NET-SysML.csproj b/src/MTConnect.NET-SysML/MTConnect.NET-SysML.csproj new file mode 100644 index 00000000..183dd9c4 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnect.NET-SysML.csproj @@ -0,0 +1,42 @@ + + + + net6.0 + MTConnect.SysML + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/src/MTConnect.NET-SysML/MTConnectClassModel.cs b/src/MTConnect.NET-SysML/MTConnectClassModel.cs new file mode 100644 index 00000000..5262cecd --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectClassModel.cs @@ -0,0 +1,101 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML +{ + public class MTConnectClassModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public bool IsAbstract { get; set; } + + public string Name { get; set; } + + public string ParentName { get; set; } + + public string Description { get; set; } + + public List Properties { get; set; } = new(); + + public Version MaximumVersion { get; set; } + + public Version MinimumVersion { get; set; } + + + public MTConnectClassModel() { } + + public MTConnectClassModel(XmiDocument xmiDocument, string id, UmlClass umlClass) + { + if (umlClass != null) + { + UmlId = umlClass.Id; + + Id = id; + Name = umlClass.Name; + IsAbstract = umlClass.IsAbstract; + + // Add SuperClass (ParentType) + if (umlClass.Generalization != null) + { + ParentName = ModelHelper.GetClassName(xmiDocument, umlClass.Generalization.General); + } + + var description = umlClass.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + + // Load Properties + var umlProperties = umlClass.Properties?.Where(o => !o.Name.StartsWith("made") && !o.Name.StartsWith("is") && !o.Name.StartsWith("observes")); + if (umlProperties != null) + { + var propertyModels = new List(); + + foreach (var umlProperty in umlProperties) + { + propertyModels.Add(new MTConnectPropertyModel(xmiDocument, id, umlProperty)); + } + + Properties = propertyModels; + } + } + } + + public void AddProperties(IEnumerable properties) + { + if (properties != null) + { + foreach (var property in properties) + { + if (!Properties.Any(o => o.Name == property.Name)) + { + Properties.Add(property); + } + } + } + } + + public static IEnumerable Parse(XmiDocument xmiDocument, string idPrefix, IEnumerable umlClasses) + { + var models = new List(); + + if (umlClasses != null) + { + foreach (var umlClass in umlClasses) + { + var id = $"{idPrefix}.{umlClass.Name.ToTitleCase()}"; + + if (!ModelHelper.IsValueClass(umlClass)) + { + models.Add(new MTConnectClassModel(xmiDocument, id, umlClass)); + } + } + } + + return models; + } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectEnumModel.cs b/src/MTConnect.NET-SysML/MTConnectEnumModel.cs new file mode 100644 index 00000000..8d85f445 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectEnumModel.cs @@ -0,0 +1,61 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML +{ + public class MTConnectEnumModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public List Values { get; set; } = new(); + + + public MTConnectEnumModel() { } + + public MTConnectEnumModel(XmiDocument xmiDocument, string idPrefix, UmlEnumeration umlEnumeration, Func convertFunction = null) + { + if (umlEnumeration != null) + { + UmlId = umlEnumeration.Id; + + var name = $"{umlEnumeration.Name.ToTitleCase()}"; + name = ModelHelper.ConvertEnumName(name) ; + + Id = $"{idPrefix}.{name}"; + Name = name; + + if (umlEnumeration.Items != null) + { + foreach (var item in umlEnumeration.Items.OrderBy(o => o.Name)) + { + Values.Add(new MTConnectEnumValueModel(Id, item, convertFunction)); + } + } + } + } + + public static IEnumerable Parse(XmiDocument xmiDocument, string idPrefix, IEnumerable umlEnumerations, Func convertFunction = null) + { + var models = new List(); + + if (umlEnumerations != null) + { + foreach (var umlEnumeration in umlEnumerations) + { + models.Add(new MTConnectEnumModel(xmiDocument, idPrefix, umlEnumeration, convertFunction)); + } + } + + return models.OrderBy(o => o.Name); + } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectEnumValueModel.cs b/src/MTConnect.NET-SysML/MTConnectEnumValueModel.cs new file mode 100644 index 00000000..ee7368c3 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectEnumValueModel.cs @@ -0,0 +1,37 @@ +using MTConnect.SysML.Xmi.UML; +using System; +using System.Linq; + +namespace MTConnect.SysML +{ + public class MTConnectEnumValueModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + + public MTConnectEnumValueModel() { } + + public MTConnectEnumValueModel(string idPrefix, UmlEnumerationLiteral enumerationLiteral, Func convertFunction = null) + { + if (enumerationLiteral != null) + { + UmlId = enumerationLiteral.Id; + + var name = enumerationLiteral.Name; + if (convertFunction != null) name = convertFunction(name); + + Id = $"{idPrefix}.{name}"; + Name = name; + + var description = enumerationLiteral.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + } + } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectModel.cs b/src/MTConnect.NET-SysML/MTConnectModel.cs new file mode 100644 index 00000000..add0d575 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectModel.cs @@ -0,0 +1,39 @@ +using MTConnect.SysML.Models.Assets; +using MTConnect.SysML.Models.Devices; +using MTConnect.SysML.Models.Observations; +using MTConnect.SysML.Xmi; +using System.Threading; + +namespace MTConnect.SysML +{ + public class MTConnectModel + { + public MTConnectDeviceInformationModel DeviceInformationModel { get; set; } + + public MTConnectObservationInformationModel ObservationInformationModel { get; set; } + + public MTConnectAssetInformationModel AssetInformationModel { get; set; } + + + public static MTConnectModel Parse(string xmiPath) + { + if (!string.IsNullOrEmpty(xmiPath)) + { + var deserializer = XmiDeserializer.FromFile(xmiPath); + var doc = deserializer.Deserialize(CancellationToken.None); + if (doc != null) + { + var mtconnectModel = new MTConnectModel(); + + mtconnectModel.DeviceInformationModel = new MTConnectDeviceInformationModel(doc); + mtconnectModel.ObservationInformationModel = new MTConnectObservationInformationModel(doc); + mtconnectModel.AssetInformationModel = new MTConnectAssetInformationModel(doc); + + return mtconnectModel; + } + } + + return null; + } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectPackageModel.cs b/src/MTConnect.NET-SysML/MTConnectPackageModel.cs new file mode 100644 index 00000000..950294ae --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectPackageModel.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace MTConnect.SysML +{ + public class MTConnectPackageModel + { + public List Classes { get; set; } = new(); + + public List Enums { get; set; } = new(); + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectPropertyModel.cs b/src/MTConnect.NET-SysML/MTConnectPropertyModel.cs new file mode 100644 index 00000000..7e4fc780 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectPropertyModel.cs @@ -0,0 +1,103 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Linq; + +namespace MTConnect.SysML +{ + public class MTConnectPropertyModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public string DataType { get; set; } + + public bool IsArray { get; set; } + + + public MTConnectPropertyModel(XmiDocument xmiDocument, string idPrefix, UmlProperty umlProperty) + { + UmlId = umlProperty.Id; + + if (xmiDocument != null && umlProperty != null) + { + IsArray = ModelHelper.IsArray(xmiDocument, umlProperty.Id); + + var propertyName = umlProperty.Name; + if (IsArray && !propertyName.EndsWith("s")) propertyName += "s"; + if (propertyName.StartsWith("has") && propertyName != "hash") propertyName = propertyName.Substring(3); + + if (propertyName == "xlink:type") propertyName = "xLinkType"; + + var name = propertyName.ToTitleCase(); + + Id = $"{idPrefix}.{name}"; + Name = name; + DataType = ParseType(xmiDocument, umlProperty.PropertyType); + + var description = umlProperty.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + if (string.IsNullOrEmpty(Description)) Description = ModelHelper.GetClassDescription(xmiDocument, umlProperty.PropertyType); + } + } + + internal static string ParseType(XmiDocument xmiDocument, string typeId) + { + if (xmiDocument != null && typeId != null) + { + switch (typeId) + { + // string + case "_19_0_3_91b028d_1579272360416_763325_681": return "string"; + + // integer + case "_19_0_3_91b028d_1579272271512_537408_674": return "int"; + + // boolean + case "_19_0_3_91b028d_1579278876899_683310_3821": return "bool"; + + // float + case "_19_0_3_91b028d_1579272506322_914606_702": return "double"; + + // DateTime + case "_19_0_3_91b028d_1579272233011_597138_670": return "System.DateTime"; + + // Description + case "EAID_64352755_7251_46af_846D_937E5A1E3949": return "Description"; + + // ID + case "_19_0_3_91b028d_1579272245466_691733_672": return "string"; + + default: + + string dataType = null; + + var dataClass = ModelHelper.GetClass(xmiDocument, typeId); + if (dataClass != null) + { + if (ModelHelper.IsValueClass(dataClass)) + { + dataType = ModelHelper.GetValueType(xmiDocument, dataClass); + } + else + { + dataType = dataClass.Name; + } + } + + + //var dataType = ModelHelper.GetClassName(xmiDocument, typeId); + if (string.IsNullOrEmpty(dataType)) dataType = ModelHelper.GetEnumName(xmiDocument, typeId); + if (string.IsNullOrEmpty(dataType)) dataType = "string"; + return dataType; + } + } + + return null; + } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectSubclassModel.cs b/src/MTConnect.NET-SysML/MTConnectSubclassModel.cs new file mode 100644 index 00000000..d70f0832 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectSubclassModel.cs @@ -0,0 +1,33 @@ +using MTConnect.SysML.Xmi.UML; +using System; +using System.Linq; + +namespace MTConnect.SysML +{ + public class MTConnectSubclassModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public Version MaximumVersion { get; set; } + + public Version MinimumVersion { get; set; } + + + public MTConnectSubclassModel(UmlClass umlClass) + { + if (umlClass != null) + { + Name = umlClass.Name; + + var description = umlClass.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + } + } + } +} diff --git a/src/MTConnect.NET-SysML/MTConnectVersion.cs b/src/MTConnect.NET-SysML/MTConnectVersion.cs new file mode 100644 index 00000000..2bbd9e92 --- /dev/null +++ b/src/MTConnect.NET-SysML/MTConnectVersion.cs @@ -0,0 +1,78 @@ +using MTConnect.SysML.Xmi; +using System; +using System.Linq; + +namespace MTConnect.SysML +{ + internal class MTConnectVersion + { + public static string GetVersionEnum(Version version) + { + if (version != null) + { + switch (version.Major) + { + case 2: + switch (version.Minor) + { + case 2: return "MTConnectVersions.Version22"; + case 1: return "MTConnectVersions.Version21"; + case 0: return "MTConnectVersions.Version20"; + } + break; + + case 1: + switch (version.Minor) + { + case 8: return "MTConnectVersions.Version18"; + case 7: return "MTConnectVersions.Version17"; + case 6: return "MTConnectVersions.Version16"; + case 5: return "MTConnectVersions.Version15"; + case 4: return "MTConnectVersions.Version14"; + case 3: return "MTConnectVersions.Version13"; + case 2: return "MTConnectVersions.Version12"; + case 1: return "MTConnectVersions.Version11"; + case 0: return "MTConnectVersions.Version10"; + } + break; + } + } + + return null; + } + + public static Version LookupNormative(XmiDocument xmiDocument, string id) + { + if (xmiDocument != null && !string.IsNullOrEmpty(id)) + { + var x = xmiDocument.NormativeIntroductions?.FirstOrDefault(o => o.BaseElement == id); + if (x != null) + { + if (Version.TryParse(x.Version, out var version)) + { + return version; + } + } + } + + return null; + } + + public static Version LookupDeprecated(XmiDocument xmiDocument, string id) + { + if (xmiDocument != null && !string.IsNullOrEmpty(id)) + { + var x = xmiDocument.Deprecations?.FirstOrDefault(o => o.BaseElement == id); + if (x != null) + { + if (Version.TryParse(x.Version, out var version)) + { + return version; + } + } + } + + return null; + } + } +} diff --git a/src/MTConnect.NET-SysML/ModelHelper.cs b/src/MTConnect.NET-SysML/ModelHelper.cs new file mode 100644 index 00000000..4667c724 --- /dev/null +++ b/src/MTConnect.NET-SysML/ModelHelper.cs @@ -0,0 +1,412 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace MTConnect.SysML +{ + internal static class ModelHelper + { + private static Dictionary _packages; + private static Dictionary _classes; + private static Dictionary _enumerations; + + + public static UmlClass GetClass(XmiDocument xmiDocument, string id) + { + if (xmiDocument != null && !string.IsNullOrEmpty(id)) + { + if (_packages == null) InitializePackages(xmiDocument); + if (_classes == null) InitializeClasses(); + + return _classes.GetValueOrDefault(id); + } + + return null; + } + + public static string GetClassName(XmiDocument xmiDocument, string id) + { + if (xmiDocument != null && !string.IsNullOrEmpty(id)) + { + if (_packages == null) InitializePackages(xmiDocument); + if (_classes == null) InitializeClasses(); + + var match = _classes.GetValueOrDefault(id); + if (match != null) return match.Name; + } + + return null; + } + + public static string GetClassDescription(XmiDocument xmiDocument, string id) + { + if (xmiDocument != null && !string.IsNullOrEmpty(id)) + { + if (_packages == null) InitializePackages(xmiDocument); + if (_classes == null) InitializeClasses(); + + var match = _classes.GetValueOrDefault(id); + if (match != null) + { + var description = match.Comments?.FirstOrDefault().Body; + return ModelHelper.ProcessDescription(description); + } + } + + return null; + } + + public static UmlEnumeration GetEnum(XmiDocument xmiDocument, string typeId) + { + if (xmiDocument != null && !string.IsNullOrEmpty(typeId)) + { + if (_packages == null) InitializePackages(xmiDocument); + if (_enumerations == null) InitializeEnumerations(); + + return _enumerations.GetValueOrDefault(typeId); + } + + return null; + } + + public static string GetEnumName(XmiDocument xmiDocument, string typeId) + { + if (xmiDocument != null && !string.IsNullOrEmpty(typeId)) + { + if (_packages == null) InitializePackages(xmiDocument); + if (_enumerations == null) InitializeEnumerations(); + + var enumeration = _enumerations.GetValueOrDefault(typeId); + if (enumeration != null) + { + return ConvertEnumName(enumeration.Name); + } + } + + return null; + } + + public static string GetEnumValue(XmiDocument xmiDocument, string typeId, string valueId) + { + if (xmiDocument != null && !string.IsNullOrEmpty(typeId) && !string.IsNullOrEmpty(valueId)) + { + if (_packages == null) InitializePackages(xmiDocument); + if (_enumerations == null) InitializeEnumerations(); + + var enumeration = _enumerations.GetValueOrDefault(typeId); + if (enumeration != null) + { + var item = enumeration.Items.FirstOrDefault(o => o.Id == valueId); + if (item != null) + { + return item.Name; + } + } + } + + return null; + } + + public static string ConvertEnumName(string name) + { + if (name != null) + { + switch (name) + { + case "CategoryEnum": name = "DataItemCategoryEnum"; break; + case "CodeEnum": name = "MeasurementCodeEnum"; break; + case "CoordinateSystemEnum": name = "DataItemCoordinateSystemEnum"; break; + case "FilterEnum": name = "FilterTypeEnum"; break; + case "NativeUnitEnum": name = "NativeUnitsEnum"; break; + case "RepresentationEnum": name = "DataItemRepresentationEnum"; break; + case "StatisticEnum": name = "DataItemStatisticEnum"; break; + case "UnitEnum": name = "UnitsEnum"; break; + } + + //var suffix = "Enum"; + //if (name.EndsWith(suffix)) name = name.Substring(0, name.Length - suffix.Length); + } + + return name; + } + + private static IEnumerable GetAllPackages(UmlModel umlModel) + { + var packages = new List(); + + foreach (var package in umlModel.Packages) + { + packages.AddRange(GetPackages(package)); + } + + foreach (var profile in umlModel.Profiles) + { + packages.AddRange(GetPackages(profile)); + } + + return packages; + } + + public static IEnumerable GetPackages(UmlPackage package) + { + var packages = new List(); + packages.Add(package); + + if (package.Packages != null) + { + foreach (var childPackage in package.Packages) + { + packages.AddRange(GetPackages(childPackage)); + } + } + + return packages; + } + + private static IEnumerable GetPackages(UmlProfile profile) + { + var packages = new List(); + + if (profile.Packages != null) + { + foreach (var childPackage in profile.Packages) + { + packages.AddRange(GetPackages(childPackage)); + } + } + + return packages; + } + + public static IEnumerable GetClasses(IEnumerable packages) + { + var classes = new List(); + + foreach (var package in packages) + { + if (package.Classes != null) + { + foreach (var packageClass in package.Classes) + { + classes.Add(packageClass); + } + } + } + + return classes; + } + + private static IEnumerable GetEnumerations(IEnumerable packages) + { + var enumerations = new List(); + + foreach (var package in packages) + { + if (package.Enumerations != null) + { + foreach (var packageEnumeration in package.Enumerations) + { + enumerations.Add(packageEnumeration); + } + } + } + + return enumerations; + } + + + private static void InitializePackages(XmiDocument xmiDocument) + { + var umlModel = xmiDocument.Model; + var packages = GetAllPackages(umlModel); + if (packages != null) + { + var dPackages = new Dictionary(); + foreach (var package in packages) + { + dPackages.Remove(package.Id); + dPackages.Add(package.Id, package); + } + _packages = dPackages; + } + } + + private static void InitializeClasses() + { + var classes = GetClasses(_packages.Values); + if (classes != null) + { + var dClasses = new Dictionary(); + + foreach (var packageClass in classes) + { + dClasses.Remove(packageClass.Id); + dClasses.Add(packageClass.Id, packageClass); + } + + _classes = dClasses; + } + } + + private static void InitializeEnumerations() + { + var enumerations = GetEnumerations(_packages.Values); + if (enumerations != null) + { + var dEnumerations = new Dictionary(); + + foreach (var packageEnumeration in enumerations) + { + dEnumerations.Remove(packageEnumeration.Id); + dEnumerations.Add(packageEnumeration.Id, packageEnumeration); + } + + _enumerations = dEnumerations; + } + } + + + public static string ProcessDescription(string text) + { + if (!string.IsNullOrEmpty(text)) + { + var regex = new Regex("\\{\\{.*?\\((.*?)\\)\\}\\}"); + var result = text; + + var matches = regex.Matches(text); + if (matches != null) + { + foreach (Match match in matches) + { + var original = match.Groups[0].Value; + var replace = match.Groups[1].Value; + + result = result.Replace(original, replace); + } + } + + result = result.Replace("\n", ""); + result = result.Replace("\r", ""); + result = UppercaseFirstWord(result); + + + //result = result.Replace(".", ". "); + //result = result.UppercaseFirstCharacter(); + + + result = result.Replace("Mtconnect", "MTConnect"); + result = result.Replace("mtconnect", "MTConnect"); + result = result.Trim(); + + return result; + } + + return null; + } + + private static string UppercaseFirstWord(string text) + { + if (text != null && text.Length > 0) + { + var words = text.Split(' '); + words[0] = words[0].UppercaseFirstCharacter(); + return string.Join(' ', words); + } + + return null; + } + + + public static bool IsArray(XmiDocument xmiDocument, string id) + { + switch (id) + { + case "_19_0_3_91b028d_1579274935610_708920_3095": return true; // Devices.Component.Components + case "_19_0_3_91b028d_1579274803419_180043_3064": return true; // Devices.Component.Compositions + case "_19_0_3_45f01b9_1581211888318_232581_149": return true; // Devices.Component.References + + case "_19_0_3_68e0225_1633431910074_887850_97": return true; // Devices.Configuration.Relationships + case "_19_0_3_68e0225_1633431923171_707595_113": return true; // Devices.Configuration.CoordinateSystems + case "_19_0_3_68e0225_1633431989416_861348_140": return true; // Devices.Configuration.Specifications + case "_19_0_3_68e0225_1677585034568_640359_707": return true; // Devices.Configuration.ImageFiles + + case "EAID_src1FD414_08E5_4c06_8E6A_D0FBEE71B296": return true; // Devices.Configruation.SensorConfiguration.Channels + + case "_19_0_3_91b028d_1579280419002_422759_4126": return true; // Devices.DataItem.Filters + case "_19_0_3_68e0225_1607601081190_91136_31": return true; // Devices.DataItem.Relationships + + case "_19_0_3_45f01b9_1581433281431_574073_286": return true; // Devices.DataItems.Definition.CellDefinitions + case "_19_0_3_45f01b9_1582939789522_356798_4412": return true; // Devices.DataItems.Definition.EntryDefinitions + + case "EAID_CB3DBE83_DB10_4aa0_9685_72CC1BEA5285": return true; // Assets.CuttingTool.Manufacturers + + case "EAID_E485DD9D_8788_4c57_B422_E3374F4215DC": return true; // Assets.CuttingToolArchetype.Manufacturers + + case "EAID_F7C32A8C_8166_4c26_839E_F946E18DB022": return true; // Assets.CuttingItem.Indices + case "EAID_9E5855C8_F90D_4ddf_A2FC_4610634008B4": return true; // Assets.CuttingItem.Manufacturers + case "_19_0_3_91b028d_1582658982276_248635_527": return true; // Assets.CuttingItem.Measurements + + case "EAID_dst8C9154_3651_4af3_9311_2AA3D0EF7282": return true; // Assets.CuttingToolLifeCycle.ToolLife + case "EAID_dstC908A3_8442_4a95_AB3E_68DFB6274CDD": return true; // Assets.CuttingToolLifeCycle.CutterStatus + case "EAID_dstAB92D5_E33E_4e6e_92EB_1FFFBF29ED9F": return true; // Assets.CuttingToolLifeCycle.CuttingItem + case "EAID_dst6C3AA0_3DE7_43bf_B6D6_22C9350D4FE2": return true; // Assets.CuttingToolLifeCycle.Measurement + + case "_19_0_3_68e0225_1622116618960_627070_1641": return true; // Assets.RawMaterial.InitialDimension + case "_19_0_3_68e0225_1622116618964_666287_1642": return true; // Assets.RawMaterial.CurrentDimension + + case "_19_0_3_68e0225_1678197264958_675939_17962": return true; // Assets.ComponentConfigurationParameters.ParameterSet + case "_19_0_3_68e0225_1678197386869_402580_18053": return true; // Assets.ParameterSet.Parameters + } + + return false; + } + + + public static bool IsValueClass(UmlClass umlClass) + { + if (umlClass != null) + { + var umlProperties = umlClass.Properties?.Where(o => !o.Name.StartsWith("made") && !o.Name.StartsWith("is") && !o.Name.StartsWith("observes")); + if (umlProperties != null && umlProperties.Count() == 1) + { + var valueProperty = umlProperties.FirstOrDefault(); + if (valueProperty != null) + { + System.Console.WriteLine(valueProperty.Name); + + return true; + } + + //var valueProperty = umlProperties.FirstOrDefault(o => o.Name == "Value"); + //if (valueProperty != null) + //{ + // return true; + //} + } + } + + return false; + } + + public static string GetValueType(XmiDocument xmiDocument, UmlClass umlClass) + { + if (umlClass != null) + { + var umlProperties = umlClass.Properties?.Where(o => !o.Name.StartsWith("made") && !o.Name.StartsWith("is") && !o.Name.StartsWith("observes")); + if (umlProperties != null && umlProperties.Count() == 1) + { + var valueProperty = umlProperties.FirstOrDefault(); + //var valueProperty = umlProperties.FirstOrDefault(o => o.Name == "Value"); + if (valueProperty != null) + { + return MTConnectPropertyModel.ParseType(xmiDocument, valueProperty.PropertyType); + } + } + } + + return "string"; + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetInformationModel.cs b/src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetInformationModel.cs new file mode 100644 index 00000000..298a3e25 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetInformationModel.cs @@ -0,0 +1,183 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Assets +{ + public class MTConnectAssetInformationModel + { + public MTConnectAssetModel Asset { get; set; } + + public MTConnectPackageModel ComponentConfigurationParameters { get; set; } = new(); + + public MTConnectPackageModel CuttingTools { get; set; } = new(); + + public MTConnectPackageModel Files { get; set; } = new(); + + public MTConnectPackageModel QIF { get; set; } = new(); + + public MTConnectPackageModel RawMaterials { get; set; } = new(); + + + public MTConnectAssetInformationModel() { } + + public MTConnectAssetInformationModel(XmiDocument xmiDocument) + { + Parse(xmiDocument); + } + + + private void Parse(XmiDocument xmiDocument) + { + if (xmiDocument != null) + { + var umlModel = xmiDocument.Model; + + // Find Information Model in the UML + var informationModel = umlModel.Packages.FirstOrDefault(o => o.Name == "Asset Information Model"); + if (informationModel != null) + { + var assetClass = informationModel.Classes.FirstOrDefault(o => o.Name == "Asset"); + Asset = new MTConnectAssetModel(xmiDocument, assetClass); + + ParseComponentConfigurationParameters(xmiDocument, informationModel); + ParseCuttingTools(xmiDocument, informationModel); + ParseFiles(xmiDocument, informationModel); + ParseQIF(xmiDocument, informationModel); + ParseRawMaterials(xmiDocument, informationModel); + } + } + } + + + private void ParseComponentConfigurationParameters(XmiDocument xmiDocument, UmlPackage umlPackage) + { + var targetPackage = umlPackage.Packages.FirstOrDefault(o => o.Name == "Component Configuration Parameters"); + if (targetPackage != null) + { + var umlPackages = ModelHelper.GetPackages(targetPackage); + var umlClasses = ModelHelper.GetClasses(umlPackages); + + var assetClasses = MTConnectClassModel.Parse(xmiDocument, "Assets.ComponentConfigurationParameters", umlClasses); + if (assetClasses != null) + { + ComponentConfigurationParameters.Classes.AddRange(assetClasses); + } + } + } + + private void ParseCuttingTools(XmiDocument xmiDocument, UmlPackage umlPackage) + { + var cuttingTool = umlPackage.Packages.FirstOrDefault(o => o.Name == "Cutting Tool"); + if (cuttingTool != null) + { + // Add Primary Classes + var packages = new List(); + packages.Add(cuttingTool); + packages.Add(cuttingTool.Packages.FirstOrDefault(o => o.Name == "Cutting Item")); + packages.Add(cuttingTool.Packages.FirstOrDefault(o => o.Name == "Cutting Tool Life Cycle")); + + var umlClasses = ModelHelper.GetClasses(packages); + var assetClasses = MTConnectClassModel.Parse(xmiDocument, "Assets.CuttingTools", umlClasses); + if (assetClasses != null) + { + CuttingTools.Classes.AddRange(assetClasses); + } + + + // Add Measurement Classes + packages.Clear(); + packages.Add(cuttingTool.Packages.FirstOrDefault(o => o.Name == "Cutting Tool Measurement Subtypes")); + + var cuttingItemPackage = cuttingTool.Packages.FirstOrDefault(o => o.Name == "Cutting Item"); + if (cuttingItemPackage != null) + { + packages.Add(cuttingItemPackage.Packages.FirstOrDefault(o => o.Name == "Cutting Item Measurement Subtypes")); + } + + umlClasses = ModelHelper.GetClasses(packages); + var measurementClasses = MTConnectCuttingToolMeasurementModel.Parse(xmiDocument, "CuttingTool", "Assets.CuttingTools.Measurements", umlClasses); + if (measurementClasses != null) + { + CuttingTools.Classes.AddRange(measurementClasses); + } + + + // Add Enums + var profile = xmiDocument.Model.Profiles.FirstOrDefault(); + var dataTypes = profile.Packages.FirstOrDefault(o => o.Name == "DataTypes"); + + CuttingTools.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.CuttingTools", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CountDirectionEnum"))); + CuttingTools.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.CuttingTools", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CutterStatusTypeEnum"))); + CuttingTools.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.CuttingTools", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "ToolLifeEnum"))); + CuttingTools.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.CuttingTools", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "LocationTypeEnum"))); + CuttingTools.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.CuttingTools", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "FormatTypeEnum"))); + CuttingTools.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.CuttingTools.Measurements", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CodeEnum"))); + } + } + + private void ParseFiles(XmiDocument xmiDocument, UmlPackage umlPackage) + { + var targetPackage = umlPackage.Packages.FirstOrDefault(o => o.Name == "Files"); + if (targetPackage != null) + { + var umlPackages = ModelHelper.GetPackages(targetPackage); + var umlClasses = ModelHelper.GetClasses(umlPackages); + var assetClasses = MTConnectClassModel.Parse(xmiDocument, "Assets.Files", umlClasses); + if (assetClasses != null) + { + Files.Classes.AddRange(assetClasses); + } + + // Add Enums + var profile = xmiDocument.Model.Profiles.FirstOrDefault(); + var dataTypes = profile.Packages.FirstOrDefault(o => o.Name == "DataTypes"); + + Files.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.Files", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "FileStateEnum"))); + } + } + + private void ParseQIF(XmiDocument xmiDocument, UmlPackage umlPackage) + { + var targetPackage = umlPackage.Packages.FirstOrDefault(o => o.Name == "QIF"); + if (targetPackage != null) + { + var umlPackages = ModelHelper.GetPackages(targetPackage); + var umlClasses = ModelHelper.GetClasses(umlPackages); + var assetClasses = MTConnectClassModel.Parse(xmiDocument, "Assets.QIF", umlClasses); + if (assetClasses != null) + { + QIF.Classes.AddRange(assetClasses); + } + + // Add Enums + var profile = xmiDocument.Model.Profiles.FirstOrDefault(); + var dataTypes = profile.Packages.FirstOrDefault(o => o.Name == "DataTypes"); + + QIF.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.QIF", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "QIFDocumentTypeEnum"))); + } + } + + private void ParseRawMaterials(XmiDocument xmiDocument, UmlPackage umlPackage) + { + var targetPackage = umlPackage.Packages.FirstOrDefault(o => o.Name == "Raw Material"); + if (targetPackage != null) + { + var umlPackages = ModelHelper.GetPackages(targetPackage); + var umlClasses = ModelHelper.GetClasses(umlPackages); + var assetClasses = MTConnectClassModel.Parse(xmiDocument, "Assets.RawMaterials", umlClasses); + if (assetClasses != null) + { + RawMaterials.Classes.AddRange(assetClasses); + } + + // Add Enums + var profile = xmiDocument.Model.Profiles.FirstOrDefault(); + var dataTypes = profile.Packages.FirstOrDefault(o => o.Name == "DataTypes"); + + RawMaterials.Enums.Add(new MTConnectEnumModel(xmiDocument, "Assets.RawMaterials", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "FormEnum"))); + } + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetModel.cs b/src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetModel.cs new file mode 100644 index 00000000..75286245 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Assets/MTConnectAssetModel.cs @@ -0,0 +1,16 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; + +namespace MTConnect.SysML.Models.Assets +{ + public class MTConnectAssetModel : MTConnectClassModel + { + public MTConnectAssetModel() { } + + public MTConnectAssetModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Assets.Asset", umlClass) + { + ParentName = null; + IsAbstract = false; + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Assets/MTConnectCuttingToolMeasurementModel.cs b/src/MTConnect.NET-SysML/Models/Assets/MTConnectCuttingToolMeasurementModel.cs new file mode 100644 index 00000000..de617be7 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Assets/MTConnectCuttingToolMeasurementModel.cs @@ -0,0 +1,83 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Assets +{ + public class MTConnectCuttingToolMeasurementModel : MTConnectClassModel + { + public string MeasurementType { get; set; } + + public string TypeId { get; set; } + + public string CodeId { get; set; } + + public string Units { get; set; } + + + public MTConnectCuttingToolMeasurementModel() { } + + public MTConnectCuttingToolMeasurementModel(XmiDocument xmiDocument, string measurementType, string idPrefix, UmlClass umlClass) : base(null, null, null) + { + if (umlClass != null) + { + UmlId = umlClass.Id; + + var name = $"{umlClass.Name.ToTitleCase()}Measurement"; + + Id = $"{idPrefix}.{name}"; + Name = name; + MeasurementType = measurementType; + TypeId = umlClass.Name.ToTitleCase(); + + var description = umlClass.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + + // Load Properties + var umlProperties = umlClass.Properties?.Where(o => !o.Name.StartsWith("made") && !o.Name.StartsWith("is") && !o.Name.StartsWith("observes")); + if (umlProperties != null) + { + foreach (var umlProperty in umlProperties) + { + // Code + if (umlProperty.Name == "code") + { + var instanceValue = umlProperty.DefaultValue as UmlInstanceValue; + if (instanceValue != null) + { + CodeId = ModelHelper.GetEnumValue(xmiDocument, umlProperty.PropertyType, instanceValue.Instance); + } + } + + // Units + if (umlProperty.Name == "units") + { + var instanceValue = umlProperty.DefaultValue as UmlInstanceValue; + if (instanceValue != null) + { + Units = ModelHelper.GetEnumValue(xmiDocument, umlProperty.PropertyType, instanceValue.Instance); + //Units = UnitsHelper.Get(Units); + } + } + } + } + } + } + + public static IEnumerable Parse(XmiDocument xmiDocument, string measurementType, string idPrefix, IEnumerable umlClasses) + { + var models = new List(); + + if (umlClasses != null) + { + foreach (var umlClass in umlClasses) + { + models.Add(new MTConnectCuttingToolMeasurementModel(xmiDocument, measurementType, idPrefix, umlClass)); + } + } + + return models.OrderBy(o => o.Name); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentModel.cs new file mode 100644 index 00000000..630e39ee --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentModel.cs @@ -0,0 +1,17 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectComponentModel : MTConnectClassModel + { + public MTConnectComponentModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Devices.Component", umlClass) + { + IsAbstract = false; + + Properties?.RemoveAll(o => o.Name == "ComponentStream"); + Properties?.RemoveAll(o => o.Name == "CompositionStream"); + Properties?.RemoveAll(o => o.Name == "DataItemStream"); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentType.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentType.cs new file mode 100644 index 00000000..c4536c16 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentType.cs @@ -0,0 +1,79 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectComponentType : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string ParentName { get; set; } + + public string Description { get; set; } + + public string DefaultName { get; set; } + + public bool IsAbstract { get; set; } + + public bool IsOrganizer { get; set; } + + public Version MaximumVersion { get; set; } + + public Version MinimumVersion { get; set; } + + + public MTConnectComponentType() { } + + public MTConnectComponentType(XmiDocument xmiDocument, string idPrefix, UmlClass umlClass, bool isOrganizer = false) + { + if (umlClass != null) + { + UmlId = umlClass.Id; + + var name = $"{umlClass.Name.ToTitleCase()}Component"; + + Id = $"{idPrefix}.{name}"; + Name = name; + DefaultName = name.ToCamelCase(); + IsAbstract = umlClass.IsAbstract; + IsOrganizer = isOrganizer; + + MaximumVersion = MTConnectVersion.LookupDeprecated(xmiDocument, umlClass.Id); + MinimumVersion = MTConnectVersion.LookupNormative(xmiDocument, umlClass.Id); + + // Add SuperClass (ParentType) + if (umlClass.Generalization != null) + { + ParentName = ModelHelper.GetClassName(xmiDocument, umlClass.Generalization.General); + if (ParentName != null && ParentName != "Component") ParentName += "Component"; + } + + var description = umlClass.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + } + } + + + public static IEnumerable Parse(XmiDocument xmiDocument, string idPrefix, IEnumerable umlClasses, bool isOrganizer = false) + { + var subClasses = new List(); + + if (umlClasses != null) + { + foreach (var umlClass in umlClasses) + { + subClasses.Add(new MTConnectComponentType(xmiDocument, idPrefix, umlClass, isOrganizer)); + } + } + + return subClasses; + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentsModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentsModel.cs new file mode 100644 index 00000000..45d905b3 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectComponentsModel.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectComponentsModel + { + public MTConnectComponentModel Component { get; set; } + + public List Types { get; set; } = new(); + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionModel.cs new file mode 100644 index 00000000..0767d939 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionModel.cs @@ -0,0 +1,20 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Collections.Generic; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectCompositionModel : MTConnectClassModel + { + public List Types { get; set; } = new(); + + + public MTConnectCompositionModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Devices.Composition", umlClass) + { + IsAbstract = false; + + Properties?.RemoveAll(o => o.Name == "Components"); + Properties?.RemoveAll(o => o.Name == "Compositions"); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionType.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionType.cs new file mode 100644 index 00000000..efcbb9cc --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionType.cs @@ -0,0 +1,64 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectCompositionType : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public string DefaultName { get; set; } + + public Version MaximumVersion { get; set; } + + public Version MinimumVersion { get; set; } + + + public MTConnectCompositionType() { } + + public MTConnectCompositionType(XmiDocument xmiDocument, string idPrefix, UmlEnumerationLiteral umlEnumerationLiteral) + { + if (umlEnumerationLiteral != null) + { + UmlId = umlEnumerationLiteral.Id; + + var name = $"{umlEnumerationLiteral.Name.ToTitleCase()}Composition"; + + Id = $"{idPrefix}.{name}"; + Name = name; + DefaultName = name.ToCamelCase(); + + MaximumVersion = MTConnectVersion.LookupDeprecated(xmiDocument, umlEnumerationLiteral.Id); + MinimumVersion = MTConnectVersion.LookupNormative(xmiDocument, umlEnumerationLiteral.Id); + + var description = umlEnumerationLiteral.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + } + } + + + public static IEnumerable Parse(XmiDocument xmiDocument, string idPrefix, UmlEnumeration umlEnumeration) + { + var subClasses = new List(); + + if (umlEnumeration != null) + { + foreach (var item in umlEnumeration.Items) + { + subClasses.Add(new MTConnectCompositionType(xmiDocument, idPrefix, item)); + } + } + + return subClasses; + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionsModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionsModel.cs new file mode 100644 index 00000000..9784dd0f --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectCompositionsModel.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectCompositionsModel + { + public MTConnectCompositionModel Composition { get; set; } + + public List Types { get; set; } = new(); + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectConfigurationModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectConfigurationModel.cs new file mode 100644 index 00000000..3faeb0e8 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectConfigurationModel.cs @@ -0,0 +1,15 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Collections.Generic; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectConfigurationModel : MTConnectClassModel + { + public List Classes { get; set; } = new(); + + public List Enums { get; set; } = new(); + + public MTConnectConfigurationModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Devices.Configurations.Configuration", umlClass) { } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemModel.cs new file mode 100644 index 00000000..fdb9a46f --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemModel.cs @@ -0,0 +1,33 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Linq; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDataItemModel : MTConnectClassModel + { + public MTConnectDataItemModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Devices.DataItem", umlClass) + { + IsAbstract = false; + + // Override Type + var typeProperty = Properties?.FirstOrDefault(o => o.Name == "Type"); + if (typeProperty != null) typeProperty.DataType = "string"; + + // Override SubType + var subtypeProperty = Properties?.FirstOrDefault(o => o.Name == "SubType"); + if (subtypeProperty != null) subtypeProperty.DataType = "string"; + + // Override Units + var unitsProperty = Properties?.FirstOrDefault(o => o.Name == "Units"); + if (unitsProperty != null) unitsProperty.DataType = "string"; + + // Override NativeUnits + var nativeUnitsProperty = Properties?.FirstOrDefault(o => o.Name == "NativeUnits"); + if (nativeUnitsProperty != null) nativeUnitsProperty.DataType = "string"; + + + Properties?.RemoveAll(o => o.Name == "Observation"); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemSubType.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemSubType.cs new file mode 100644 index 00000000..5a8290a1 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemSubType.cs @@ -0,0 +1,27 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Linq; +using System.Text.RegularExpressions; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDataItemSubType : MTConnectSubclassModel + { + public MTConnectDataItemSubType(XmiDocument xmiDocument, string idPrefix, UmlClass umlClass) : base(null) + { + UmlId = umlClass.Id; + + var regex = new Regex("^.*\\.(.*)$"); + var name = regex.Match(umlClass.Name).Groups[1].Value; + + Id = $"{idPrefix}.{name}"; + Name = name.ToUnderscoreUpper(); + + MaximumVersion = MTConnectVersion.LookupDeprecated(xmiDocument, umlClass.Id); + MinimumVersion = MTConnectVersion.LookupNormative(xmiDocument, umlClass.Id); + + var description = umlClass.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemType.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemType.cs new file mode 100644 index 00000000..f5ab4a29 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemType.cs @@ -0,0 +1,148 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDataItemType : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public string Category { get; set; } + + public string Type { get; set; } + + public string ParentName { get; set; } + + public string Representation { get; set; } + + public string Units { get; set; } + + public string DefaultSubType { get; set; } + + public string Result { get; set; } + + public Version MaximumVersion { get; set; } + + public Version MinimumVersion { get; set; } + + public List SubTypes { get; set; } + + + public MTConnectDataItemType() { } + + public MTConnectDataItemType(XmiDocument xmiDocument, string category, string idPrefix, UmlClass umlClass, UmlEnumerationLiteral umlEnumerationLiteral, IEnumerable subClasses = null) + { + if (umlClass != null && umlEnumerationLiteral != null) + { + UmlId = umlClass.Id; + + var name = $"{umlClass.Name.ToTitleCase()}DataItem"; + + Id = $"{idPrefix}.{name}"; + Name = name; + Category = category; + Type = umlClass.Name.ToUnderscoreUpper(); + + var description = umlEnumerationLiteral.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + + MaximumVersion = MTConnectVersion.LookupDeprecated(xmiDocument, umlClass.Id); + MinimumVersion = MTConnectVersion.LookupNormative(xmiDocument, umlClass.Id); + + // Add SuperClass (ParentType) + if (umlClass.Generalization != null) + { + ParentName = ModelHelper.GetClassName(xmiDocument, umlClass.Generalization.General); + if (ParentName != null && ParentName != "DataItem") ParentName += "DataItem"; + } + + if (umlClass.Properties != null) + { + foreach (var property in umlClass.Properties) + { + // Default SubType + if (property.Name == "subType") + { + var instanceValue = property.DefaultValue as UmlInstanceValue; + if (instanceValue != null) + { + DefaultSubType = ModelHelper.GetEnumValue(xmiDocument, property.PropertyType, instanceValue.Instance); + } + } + + // Result + if (property.Name == "result") + { + // Get Class (TABLE OR DATA_SET) + Result = ModelHelper.GetClassName(xmiDocument, property.PropertyType); + + if (Result == null) + { + // Get Enum (EVENT) + Result = ModelHelper.GetEnumName(xmiDocument, property.PropertyType); + Representation = "VALUE"; + } + else + { + Representation = "TABLE"; // Should probably take into account DATA_SET as well? + } + } + + // Units + if (property.Name == "units") + { + var instanceValue = property.DefaultValue as UmlInstanceValue; + if (instanceValue != null) + { + Units = ModelHelper.GetEnumValue(xmiDocument, property.PropertyType, instanceValue.Instance); + //Units = UnitsHelper.Get(Units); + } + } + } + } + + if (subClasses != null) + { + var subTypes = new List(); + foreach (var subClass in subClasses) + { + subTypes.Add(new MTConnectDataItemSubType(xmiDocument, Id, subClass)); + } + SubTypes = subTypes; + } + } + } + + + public static IEnumerable Parse(XmiDocument xmiDocument, string category, string idPrefix, IEnumerable umlClasses, UmlEnumeration umlEnumeration) + { + var types = new List(); + + if (umlClasses != null && umlEnumeration != null) + { + foreach (var umlClass in umlClasses) + { + // Filter out SubTypes (ex. Type.Subtype) + if (!umlClass.Name.Contains('.')) + { + var enumItem = umlEnumeration.Items.FirstOrDefault(o => o.Name.ToTitleCase() == umlClass.Name); + var subClasses = umlClasses.Where(o => o.Name.StartsWith($"{umlClass.Name}.")); + + types.Add(new MTConnectDataItemType(xmiDocument, category, idPrefix, umlClass, enumItem, subClasses)); + } + } + } + + return types.OrderBy(o => o.Name); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemsModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemsModel.cs new file mode 100644 index 00000000..9458bb98 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDataItemsModel.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDataItemsModel + { + public MTConnectDataItemModel DataItem { get; set; } + + public List Types { get; set; } = new(); + + public List Classes { get; set; } = new(); + + public List Enums { get; set; } = new(); + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDescriptionModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDescriptionModel.cs new file mode 100644 index 00000000..b40c6828 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDescriptionModel.cs @@ -0,0 +1,10 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDescriptionModel : MTConnectClassModel + { + public MTConnectDescriptionModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Devices.Description", umlClass) { } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceInformationModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceInformationModel.cs new file mode 100644 index 00000000..4b983178 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceInformationModel.cs @@ -0,0 +1,162 @@ +using MTConnect.SysML.Xmi; +using System.Linq; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDeviceInformationModel + { + public MTConnectDeviceModel Device { get; private set; } + + public MTConnectComponentsModel Components { get; private set; } + + public MTConnectCompositionsModel Compositions { get; private set; } + + public MTConnectDataItemsModel DataItems { get; private set; } + + public MTConnectDescriptionModel Description { get; private set; } + + public MTConnectConfigurationModel Configurations { get; private set; } + + + public MTConnectDeviceInformationModel() { } + + public MTConnectDeviceInformationModel(XmiDocument xmiDocument) + { + Parse(xmiDocument); + } + + + private void Parse(XmiDocument xmiDocument) + { + if (xmiDocument != null) + { + var umlModel = xmiDocument.Model; + + // Find Device Information Model in the UML + var deviceInformationModel = umlModel.Packages.FirstOrDefault(o => o.Name == "Device Information Model"); + var observationInformationModel = umlModel.Packages.FirstOrDefault(o => o.Name == "Observation Information Model"); + if (deviceInformationModel != null && observationInformationModel != null) + { + // Components + var components = deviceInformationModel.Packages?.FirstOrDefault(o => o.Name == "Components"); + if (components != null) + { + Components = new MTConnectComponentsModel(); + + // Component + var componentClass = components.Classes?.FirstOrDefault(o => o.Name == "Component"); + Components.Component = new MTConnectComponentModel(xmiDocument, componentClass); + + var componentTypes = components.Packages?.FirstOrDefault(o => o.Name == "Component Types"); + Components.Types.AddRange(MTConnectComponentType.Parse(xmiDocument, "Devices.Components", componentTypes.Classes)); + + var componentOrganizerTypes = componentTypes.Packages?.FirstOrDefault(o => o.Name == "Component Organizer Types"); + Components.Types.AddRange(MTConnectComponentType.Parse(xmiDocument, "Devices.Components", componentOrganizerTypes.AssociationClasses, true)); + + // Description + var descriptionClass = components.Classes?.FirstOrDefault(o => o.Name == "Description"); + Description = new MTConnectDescriptionModel(xmiDocument, descriptionClass); + } + + + // Device + var deviceClass = deviceInformationModel.Classes?.FirstOrDefault(); + Device = new MTConnectDeviceModel(xmiDocument, deviceClass); + Device.AddProperties(Components.Component.Properties); + + + // Compositions + var compositions = deviceInformationModel.Packages?.FirstOrDefault(o => o.Name == "Compositions"); + if (compositions != null) + { + Compositions = new MTConnectCompositionsModel(); + + // Composition + var compositionClass = compositions.Classes?.FirstOrDefault(o => o.Name == "Composition"); + Compositions.Composition = new MTConnectCompositionModel(xmiDocument, compositionClass); + Compositions.Composition.AddProperties(Components.Component.Properties); + + // Composition Types + var compositionEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "CompositionTypeEnum"); + Compositions.Types.AddRange(MTConnectCompositionType.Parse(xmiDocument, "Devices.Compositions", compositionEnum)); + } + + + // DataItems + var deviceDataItems = deviceInformationModel.Packages?.FirstOrDefault(o => o.Name == "DataItems"); + if (deviceDataItems != null) + { + DataItems = new MTConnectDataItemsModel(); + + // DataItem + var dataItemClass = deviceDataItems.Classes?.FirstOrDefault(o => o.Name == "DataItem"); + DataItems.DataItem = new MTConnectDataItemModel(xmiDocument, dataItemClass); + + // DataItem Properties + var dataItemProperties = deviceDataItems.Packages?.FirstOrDefault(o => o.Name == "Properties of DataItem"); + if (dataItemProperties != null) + { + DataItems.Classes.AddRange(MTConnectClassModel.Parse(xmiDocument, "Devices", dataItemProperties.Classes)); + } + + var observationTypes = observationInformationModel.Packages?.FirstOrDefault(o => o.Name == "Observation Types"); + if (observationTypes != null) + { + var conditionEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "ConditionEnum"); + var conditionTypes = observationTypes.Packages?.FirstOrDefault(o => o.Name == "Condition Types"); + DataItems.Types.AddRange(MTConnectDataItemType.Parse(xmiDocument, "CONDITION", "Devices.DataItems", conditionTypes.Classes, conditionEnum)); + + var eventEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "EventEnum"); + var eventTypes = observationTypes.Packages?.FirstOrDefault(o => o.Name == "Event Types"); + DataItems.Types.AddRange(MTConnectDataItemType.Parse(xmiDocument, "EVENT", "Devices.DataItems", eventTypes.Classes, eventEnum)); + + var sampleEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "SampleEnum"); + var sampleTypes = observationTypes.Packages?.FirstOrDefault(o => o.Name == "Sample Types"); + DataItems.Types.AddRange(MTConnectDataItemType.Parse(xmiDocument, "SAMPLE", "Devices.DataItems", sampleTypes.Classes, sampleEnum)); + } + + // Add Enums + var profile = xmiDocument.Model.Profiles.FirstOrDefault(); + var dataTypes = profile.Packages.FirstOrDefault(o => o.Name == "DataTypes"); + + DataItems.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "UnitEnum"))); + DataItems.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "NativeUnitEnum"))); + DataItems.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CategoryEnum"))); + DataItems.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CoordinateSystemEnum"))); + DataItems.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "RepresentationEnum"))); + DataItems.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "StatisticEnum"))); + } + + + // Configurations + var configurations = deviceInformationModel.Packages?.FirstOrDefault(o => o.Name == "Configurations"); + if (configurations != null) + { + // Configuration + var configurationClass = configurations.Classes?.FirstOrDefault(o => o.Name == "Configuration"); + Configurations = new MTConnectConfigurationModel(xmiDocument, configurationClass); + + foreach (var package in configurations.Packages) + { + Configurations.Classes.AddRange(MTConnectClassModel.Parse(xmiDocument, "Devices.Configurations", package.Classes)); + } + + + // Add Enums + var profile = xmiDocument.Model.Profiles.FirstOrDefault(); + var dataTypes = profile.Packages.FirstOrDefault(o => o.Name == "DataTypes"); + + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CoordinateSystemTypeEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "MediaTypeEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "MotionActuationTypeEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "MotionTypeEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "RelationshipTypeEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "CriticalityEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "RoleTypeEnum"))); + Configurations.Enums.Add(new MTConnectEnumModel(xmiDocument, "Devices.Configurations", dataTypes?.Enumerations.FirstOrDefault(o => o.Name == "OriginatorEnum"))); + } + } + } + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceModel.cs b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceModel.cs new file mode 100644 index 00000000..e7a1e371 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Devices/MTConnectDeviceModel.cs @@ -0,0 +1,32 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Linq; + +namespace MTConnect.SysML.Models.Devices +{ + public class MTConnectDeviceModel : MTConnectClassModel + { + public MTConnectDeviceModel(XmiDocument xmiDocument, UmlClass umlClass) : base(xmiDocument, "Devices.Device", umlClass) + { + IsAbstract = false; + + // Override MTConnectVersion (to fix case) + var mtconnectVersionProperty = Properties?.FirstOrDefault(o => o.Name?.ToLower() == "mtconnectversion"); + if (mtconnectVersionProperty != null) mtconnectVersionProperty.Name = "MTConnectVersion"; + + Properties?.RemoveAll(o => o.Name == "Adapter"); + Properties?.RemoveAll(o => o.Name == "Auxiliary"); + Properties?.RemoveAll(o => o.Name == "Axis"); + Properties?.RemoveAll(o => o.Name == "ComponentStream"); + Properties?.RemoveAll(o => o.Name == "CompositionStream"); + Properties?.RemoveAll(o => o.Name == "Controller"); + Properties?.RemoveAll(o => o.Name == "DataItemStream"); + Properties?.RemoveAll(o => o.Name == "Interface"); + Properties?.RemoveAll(o => o.Name == "Resource"); + Properties?.RemoveAll(o => o.Name == "Part"); + Properties?.RemoveAll(o => o.Name == "Process"); + Properties?.RemoveAll(o => o.Name == "Structure"); + Properties?.RemoveAll(o => o.Name == "System"); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationInformationModel.cs b/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationInformationModel.cs new file mode 100644 index 00000000..7fe3310c --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationInformationModel.cs @@ -0,0 +1,52 @@ +using MTConnect.SysML.Xmi; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Observations +{ + public class MTConnectObservationInformationModel + { + public List Models { get; set; } = new(); + + + public MTConnectObservationInformationModel() { } + + public MTConnectObservationInformationModel(XmiDocument xmiDocument) + { + Parse(xmiDocument); + } + + + private void Parse(XmiDocument xmiDocument) + { + if (xmiDocument != null) + { + var umlModel = xmiDocument.Model; + + // Find Information Model in the UML + var informationModel = umlModel.Packages.FirstOrDefault(o => o.Name == "Observation Information Model"); + if (informationModel != null) + { + var observationTypesPackage = informationModel.Packages.FirstOrDefault(o => o.Name == "Observation Types"); + if (observationTypesPackage != null) + { + // Conditions + var conditionEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "ConditionEnum"); + var conditionValues = observationTypesPackage.Packages.FirstOrDefault(o => o.Name == "Condition Types"); + Models.AddRange(MTConnectObservationModel.Parse(xmiDocument, "Condition", "Observations.Conditions", conditionValues.Classes, conditionEnum)); + + // Events + var eventEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "EventEnum"); + var eventValues = observationTypesPackage.Packages.FirstOrDefault(o => o.Name == "Event Types"); + Models.AddRange(MTConnectObservationModel.Parse(xmiDocument, "Event", "Observations.Events", eventValues.Classes, eventEnum)); + + // Samples + var sampleEnum = umlModel.Profiles.FirstOrDefault().Packages.FirstOrDefault().Enumerations.FirstOrDefault(o => o.Name == "SampleEnum"); + var sampleValues = observationTypesPackage.Packages.FirstOrDefault(o => o.Name == "Sample Types"); + Models.AddRange(MTConnectObservationModel.Parse(xmiDocument, "Sample", "Observations.Samples", sampleValues.Classes, sampleEnum)); + } + } + } + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationModel.cs b/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationModel.cs new file mode 100644 index 00000000..f5a9d772 --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationModel.cs @@ -0,0 +1,75 @@ +using MTConnect.SysML.Xmi; +using MTConnect.SysML.Xmi.UML; +using System.Collections.Generic; +using System.Linq; + +namespace MTConnect.SysML.Models.Observations +{ + public class MTConnectObservationModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public List Values { get; set; } = new(); + + + public MTConnectObservationModel() { } + + public MTConnectObservationModel(XmiDocument xmiDocument, string category, string idPrefix, UmlClass umlClass, UmlEnumerationLiteral umlEnumerationLiteral, UmlEnumeration resultEnumeration) + { + if (umlClass != null) + { + var name = $"{umlClass.Name.ToTitleCase()}"; + + Id = $"{idPrefix}.{name}"; + Name = name; + + var description = umlEnumerationLiteral?.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + + if (resultEnumeration != null) + { + foreach (var item in resultEnumeration.Items) + { + Values.Add(new MTConnectObservationValueModel(Id, item)); + } + } + } + } + + public static IEnumerable Parse(XmiDocument xmiDocument, string category, string idPrefix, IEnumerable umlClasses, UmlEnumeration umlEnumeration) + { + var models = new List(); + + if (umlClasses != null) + { + foreach (var umlClass in umlClasses) + { + // Filter out SubTypes (ex. Type.Subtype) + if (!umlClass.Name.Contains('.')) + { + var enumItem = umlEnumeration.Items.FirstOrDefault(o => o.Name.ToTitleCase() == umlClass.Name); + + // Result + var resultProperty = umlClass.Properties?.FirstOrDefault(o => o.Name == "result"); + if (resultProperty != null) + { + var resultEnumeration = ModelHelper.GetEnum(xmiDocument, resultProperty.PropertyType); + if (resultEnumeration != null) + { + models.Add(new MTConnectObservationModel(xmiDocument, category, idPrefix, umlClass, enumItem, resultEnumeration)); + } + } + } + } + } + + return models.OrderBy(o => o.Name); + } + } +} diff --git a/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationValueModel.cs b/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationValueModel.cs new file mode 100644 index 00000000..47019e4a --- /dev/null +++ b/src/MTConnect.NET-SysML/Models/Observations/MTConnectObservationValueModel.cs @@ -0,0 +1,35 @@ +using MTConnect.SysML.Xmi.UML; +using System.Linq; + +namespace MTConnect.SysML.Models.Observations +{ + public class MTConnectObservationValueModel : IMTConnectExportModel + { + public string UmlId { get; set; } + + public string Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + + public MTConnectObservationValueModel() { } + + public MTConnectObservationValueModel(string idPrefix, UmlEnumerationLiteral enumerationLiteral) + { + if (enumerationLiteral != null) + { + UmlId = enumerationLiteral.Id; + + var name = enumerationLiteral.Name; + + Id = $"{idPrefix}.{name}"; + Name = name; + + var description = enumerationLiteral.Comments?.FirstOrDefault().Body; + Description = ModelHelper.ProcessDescription(description); + } + } + } +} diff --git a/src/MTConnect.NET-SysML/Xmi/AnnotatedElement.cs b/src/MTConnect.NET-SysML/Xmi/AnnotatedElement.cs new file mode 100644 index 00000000..1702a6dd --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/AnnotatedElement.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <annotatedElement /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.ANNOTATED_ELEMENT, Namespace = "")] + public class AnnotatedElement + { + /// + /// xmi:idref attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.idRef, Namespace = XmiHelper.XmiNamespace)] + public string? IdRef { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Association.cs b/src/MTConnect.NET-SysML/Xmi/Association.cs new file mode 100644 index 00000000..d5b410bb --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Association.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <assocation /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.ASSOCIATION, Namespace = "")] + public class Association + { + /// + /// href attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.href, Namespace = "")] + public string? Href { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/ConstrainedElement.cs b/src/MTConnect.NET-SysML/Xmi/ConstrainedElement.cs new file mode 100644 index 00000000..d366bc5d --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/ConstrainedElement.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <constrainedElement /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.CONSTRAINED_ELEMENT, Namespace = "")] + public class ConstrainedElement : XmiElement + { + /// + /// xmi:idref attribute + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.idRef, Namespace = XmiHelper.XmiNamespace)] + public string? IdRef { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/DefaultValue.cs b/src/MTConnect.NET-SysML/Xmi/DefaultValue.cs new file mode 100644 index 00000000..88f5b760 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/DefaultValue.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <defaultValue /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.DEFAULT_VALUE, Namespace = "")] + public class DefaultValue : XmiElement + { + + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Generalization.cs b/src/MTConnect.NET-SysML/Xmi/Generalization.cs new file mode 100644 index 00000000..132ab33d --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Generalization.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <generalization /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.GENERALIZATION, Namespace = "")] + public class Generalization : XmiElement + { + // TODO: Add general, general#href + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/IXmiElement.cs b/src/MTConnect.NET-SysML/Xmi/IXmiElement.cs new file mode 100644 index 00000000..1d4194bb --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/IXmiElement.cs @@ -0,0 +1,23 @@ +namespace MTConnect.SysML.Xmi +{ + /// + /// Generic reference to a xmi element + /// + public interface IXmiElement + { + /// + /// xmi:id attribute + /// + string? Id { get; set; } + + /// + /// name attribute + /// + string? Name { get; set; } + + /// + /// xmi:type attribute + /// + string? Type { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/LowerValue.cs b/src/MTConnect.NET-SysML/Xmi/LowerValue.cs new file mode 100644 index 00000000..80bb1125 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/LowerValue.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <lowerValue /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.LOWER_VALUE, Namespace = "")] + public class LowerValue : XmiElement + { + /// + /// value attribute + /// + [XmlAttribute(XmiHelper.XmiStructure.value, Namespace = "")] + public string? Value { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/MemberEnd.cs b/src/MTConnect.NET-SysML/Xmi/MemberEnd.cs new file mode 100644 index 00000000..efc0e9af --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/MemberEnd.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <memberEnd /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.MEMBER_END, Namespace = "")] + public class MemberEnd : XmiElement + { + /// + /// xmi:idref attribute + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.idRef, Namespace = XmiHelper.XmiNamespace)] + public string? IdRef { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/MetamodelReference.cs b/src/MTConnect.NET-SysML/Xmi/MetamodelReference.cs new file mode 100644 index 00000000..229d79e2 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/MetamodelReference.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <metamodelReference /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.METAMODEL_REFERENCE, Namespace = "")] + public class MetamodelReference : XmiElement + { + /// + /// xmi:idref attribute + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.idRef, Namespace = XmiHelper.XmiNamespace)] + public string? IdRef { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/ModelExtension.cs b/src/MTConnect.NET-SysML/Xmi/ModelExtension.cs new file mode 100644 index 00000000..a5714979 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/ModelExtension.cs @@ -0,0 +1,24 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <modelExtension /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.MODEL_EXTENSION, Namespace = "")] + public class ModelExtension + { + /// + /// Child + /// + [XmlElement(XmiHelper.XmiStructure.UPPER_VALUE, Namespace = "")] + public UpperValue? UpperValue { get; set; } + + /// + /// Child + /// + [XmlElement(XmiHelper.XmiStructure.LOWER_VALUE, Namespace = "")] + public LowerValue? LowerValue { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedAttribute.cs b/src/MTConnect.NET-SysML/Xmi/OwnedAttribute.cs new file mode 100644 index 00000000..bb533025 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedAttribute.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedAttribute /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_ATTRIBUTE, Namespace = "")] + public class OwnedAttribute : XmiElement + { + + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedComment.cs b/src/MTConnect.NET-SysML/Xmi/OwnedComment.cs new file mode 100644 index 00000000..e95f39b5 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedComment.cs @@ -0,0 +1,31 @@ +using MTConnect.SysML.Xmi.UML; +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedComment /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + [XmlInclude(typeof(UmlComment))] + public class OwnedComment : XmiElement { + /// + /// body attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.BODY, Namespace = "")] + public string? Body { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public OwnedComment? SubComment { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.ANNOTATED_ELEMENT, Namespace = "")] + public AnnotatedElement? AnnotatedElement { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedEnd.cs b/src/MTConnect.NET-SysML/Xmi/OwnedEnd.cs new file mode 100644 index 00000000..ad769e21 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedEnd.cs @@ -0,0 +1,40 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedEnd /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_END, Namespace = "")] + public class OwnedEnd : XmiElement + { + /// + /// visibility attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.visibility, Namespace = "")] + public string? Visibility { get; set; } + + /// + /// aggregation attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.aggregation, Namespace = "")] + public string? Aggregation { get; set; } + + /// + /// type attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.type, Namespace = "")] + public string? TypeId { get; set; } + + /// + /// association attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.association, Namespace = "")] + public string? Association { get; set; } + + // TODO: Add lowerValue + // TODO: Add xmi:Extension; + // TODO: Handle variants of attributes as elements. For example, if type is not an attribute it could be an element. + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedLiteral.cs b/src/MTConnect.NET-SysML/Xmi/OwnedLiteral.cs new file mode 100644 index 00000000..8487eafb --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedLiteral.cs @@ -0,0 +1,11 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedLiteral /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_LITERAL, Namespace = "")] + public class OwnedLiteral : XmiElement { } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedOperation.cs b/src/MTConnect.NET-SysML/Xmi/OwnedOperation.cs new file mode 100644 index 00000000..c9387eb5 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedOperation.cs @@ -0,0 +1,36 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedOperation /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_OPERATION, Namespace = "")] + public class OwnedOperation : XmiElement + { + /// + /// visibility attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.visibility, Namespace = "")] + public string? Visibility { get; set; } + + /// + /// isQuery attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.isQuery, Namespace = "")] + public bool isQuery { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT)] + public OwnedComment[]? Comment { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_PARAMETER)] + public OwnedParameter[]? Parameters { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedParameter.cs b/src/MTConnect.NET-SysML/Xmi/OwnedParameter.cs new file mode 100644 index 00000000..ce6f5af2 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedParameter.cs @@ -0,0 +1,24 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedParameter /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_PARAMETER, Namespace = "")] + public class OwnedParameter : XmiElement + { + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public OwnedComment[]? Comments { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.DEFAULT_VALUE, Namespace = "")] + public DefaultValue? DefaultValue { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/OwnedRule.cs b/src/MTConnect.NET-SysML/Xmi/OwnedRule.cs new file mode 100644 index 00000000..0e978eb2 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/OwnedRule.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <ownedRule /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_RULE, Namespace = "")] + public class OwnedRule : XmiElement + { + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.SPECIFICATION, Namespace = "")] + public Specification? Specification { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/PackageImport.cs b/src/MTConnect.NET-SysML/Xmi/PackageImport.cs new file mode 100644 index 00000000..2170579e --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/PackageImport.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <packageImport /> element + /// + [Serializable, XmlType(AnonymousType = true, Namespace = ""), XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGE_IMPORT, Namespace = "")] + public class PackageImport : XmiElement + { + // TODO: Add importedPackage + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/PackagedElement.cs b/src/MTConnect.NET-SysML/Xmi/PackagedElement.cs new file mode 100644 index 00000000..af5ef119 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/PackagedElement.cs @@ -0,0 +1,22 @@ +using MTConnect.SysML.Xmi.UML; +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <packagedElement /> element + /// + [Serializable, XmlType(Namespace = XmiHelper.UmlNamespace), XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = XmiHelper.UmlNamespace)] + [XmlInclude(typeof(UmlPackage)), + XmlInclude(typeof(UmlProfile)), + XmlInclude(typeof(UmlClass)), + XmlInclude(typeof(UmlEnumeration)), + XmlInclude(typeof(UmlExtension)), + XmlInclude(typeof(UmlPrimitiveType)), + XmlInclude(typeof(UmlStereotype))] + public class PackagedElement : XmiElement + { + + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/PackagedElementCollection.cs b/src/MTConnect.NET-SysML/Xmi/PackagedElementCollection.cs new file mode 100644 index 00000000..50fa1521 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/PackagedElementCollection.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// A collection of <packagedElement /> elements of a specific xmi:type. + /// + /// + public class PackagedElementCollection : ICollection where T : PackagedElement + { + private List Items = new List(); + + private Dictionary NameCache = new Dictionary(); + private Dictionary IdCache = new Dictionary(); + private HashSet Cache = new HashSet(); + + /// + /// Gets the element by the name attribute + /// + /// Term to lookup the element by name + /// First <packagedElement /> where the name matched. Returns null if no elements were found + public T GetByName(string? name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException(nameof(name)); + int index = -1; + if (NameCache.TryGetValue(name!, out index)) + return Items.ElementAt(index); + + return Get((e) => e.Name!.Equals(name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + } + + /// + /// Gets the element by the xmi:id attribute + /// + /// Term to lookup the element by id + /// First <packagedElement /> where the id matched. Returns null if no elements were found + public T GetById(string? id) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + int index = -1; + if (IdCache.TryGetValue(id!, out index)) + return Items.ElementAt(index); + + return Get((e) => e.Id!.Equals(id, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + } + + private IEnumerable Get(Func eval) + { + for (int i = 0; i < Items.Count; i++) + { + if (Cache.Contains(i)) continue; + var element = Items.ElementAt(i); + if (element != null && eval(element)) + { + if (!string.IsNullOrEmpty(element.Name) && !NameCache.ContainsKey(element.Name!)) + NameCache.Add(element.Name!, i); + + if (!string.IsNullOrEmpty(element.Id) && !IdCache.ContainsKey(element.Id!)) + IdCache.Add(element.Id!, i); + + Cache.Add(i); + + yield return element; + } + } + } + + /// + public int Count => Items.Count; + + /// + public bool IsReadOnly => true; + + /// + public void Add(T item) + { + int index = Items.Count; + Items.Add(item); + + if (!string.IsNullOrEmpty(item.Name) && !NameCache.ContainsKey(item.Name!)) + NameCache.Add(item.Name!, index); + + if (!string.IsNullOrEmpty(item.Id) && !IdCache.ContainsKey(item.Id!)) + IdCache.Add(item.Id!, index); + + if (!Cache.Contains(index)) + Cache.Add(index); + } + + /// + public void Clear() + => Items.Clear(); + + /// + public bool Contains(T item) + => Items.Contains(item); + + /// + public void CopyTo(T[] array, int arrayIndex) + => Items.CopyTo(array, arrayIndex); + + /// + public IEnumerator GetEnumerator() + => Items.GetEnumerator(); + + /// + public bool Remove(T item) + { + int index = Items.IndexOf(item); + + if (Items.Remove(item)) + { + string[] keys = NameCache.Where(o => o.Value > index) + .Select(kvp => kvp.Key) + .ToArray(); + Cache.RemoveWhere(o => o > index); + for (int i = index; i < Items.Count; i++) + { + NameCache[NameCache.ElementAt(i).Key]--; + IdCache[IdCache.ElementAt(i).Key]--; + } + + return true; + } + + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + /// Deserializes the XmlElement(s) into the provided . + /// + /// Collection of XmlElement(s) to deserialize. + /// Reference to the xmi:type to filter the by. + /// + public static PackagedElementCollection Deserialize(XmlElement[]? elements, string type) + { + var result = new PackagedElementCollection(); + if (elements == null) + return result; + + XmlRootAttribute xRoot = new XmlRootAttribute + { + ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, + IsNullable = true, + Namespace = "" + }; + XmlSerializer serial = new XmlSerializer(typeof(T), xRoot); + foreach (var element in elements) + { + if (element.LocalName != XmiHelper.XmiStructure.PACKAGED_ELEMENT || !element.GetAttribute("type", XmiHelper.XmiNamespace).Equals(type)) + continue; + + using var xReader = new XmlNodeReader(element); + object? deserializedObject = serial.Deserialize(xReader); + if (deserializedObject == null) + continue; + if (!(deserializedObject is T typedObject)) + continue; + + result.Add(typedObject); + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/Deprecated.cs b/src/MTConnect.NET-SysML/Xmi/Profile/Deprecated.cs new file mode 100644 index 00000000..fb1da5df --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/Deprecated.cs @@ -0,0 +1,25 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:deprecated /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.DEPRECATED, Namespace = XmiHelper.ProfileNamespace)] + public class Deprecated : ProfileElement + { + /// + /// base_Element attribute + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseElement, Namespace = "")] + public string? BaseElement { get; set; } + + /// + /// version attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.version, Namespace = "")] + public string? Version { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/Extensible.cs b/src/MTConnect.NET-SysML/Xmi/Profile/Extensible.cs new file mode 100644 index 00000000..4c194807 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/Extensible.cs @@ -0,0 +1,19 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:extensible /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.EXTENSIBLE, Namespace = XmiHelper.ProfileNamespace)] + public class Extensible : ProfileElement + { + /// + /// base_Enumeration attribute. + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseEnumeration, Namespace = "")] + public string? BaseEnumeration { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/Informative.cs b/src/MTConnect.NET-SysML/Xmi/Profile/Informative.cs new file mode 100644 index 00000000..61e36af5 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/Informative.cs @@ -0,0 +1,19 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:informative /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.INFORMATIVE, Namespace = XmiHelper.ProfileNamespace)] + public class Informative : ProfileElement + { + /// + /// base_Element attribute. + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseElement, Namespace = "")] + public string? BaseElement { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/Normative.cs b/src/MTConnect.NET-SysML/Xmi/Profile/Normative.cs new file mode 100644 index 00000000..a1ec7ebd --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/Normative.cs @@ -0,0 +1,25 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:normative /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.NORMATIVE, Namespace = XmiHelper.ProfileNamespace)] + public class Normative : ProfileElement + { + /// + /// base_Element attribute + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseElement, Namespace = "")] + public string? BaseElement { get; set; } + + /// + /// version attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.version, Namespace = "")] + public string? Version { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/Observes.cs b/src/MTConnect.NET-SysML/Xmi/Profile/Observes.cs new file mode 100644 index 00000000..474406b0 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/Observes.cs @@ -0,0 +1,19 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:observes /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.OBSERVES, Namespace = XmiHelper.ProfileNamespace)] + public class Observes : ProfileElement + { + /// + /// base_Association attribute. + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseAssociation, Namespace = "")] + public string? BaseAssociation { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/Organizer.cs b/src/MTConnect.NET-SysML/Xmi/Profile/Organizer.cs new file mode 100644 index 00000000..def56787 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/Organizer.cs @@ -0,0 +1,19 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:organizer /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.ORGANIZER, Namespace = XmiHelper.ProfileNamespace)] + public class Organizer : ProfileElement + { + /// + /// base_Element attribute. + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseElement, Namespace = "")] + public string? BaseElement { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/ProfileElement.cs b/src/MTConnect.NET-SysML/Xmi/Profile/ProfileElement.cs new file mode 100644 index 00000000..c7ca4cf3 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/ProfileElement.cs @@ -0,0 +1,16 @@ +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:x /> element + /// + public abstract class ProfileElement + { + /// + /// Unique ID within the XMI. + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.id, Namespace = XmiHelper.XmiNamespace)] + public virtual string? Id { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Profile/ValueType.cs b/src/MTConnect.NET-SysML/Xmi/Profile/ValueType.cs new file mode 100644 index 00000000..8c6ccba4 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Profile/ValueType.cs @@ -0,0 +1,19 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.Profile +{ + /// + /// <Profile:valueType /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.ProfileStructure.VALUE_TYPE, Namespace = XmiHelper.ProfileNamespace)] + public class ValueType : ProfileElement + { + /// + /// base_Class attribute. + /// + /// Foreign key to the of the object this applies to. + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.baseClass, Namespace = "")] + public string? BaseClass { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/RedefinedProperty.cs b/src/MTConnect.NET-SysML/Xmi/RedefinedProperty.cs new file mode 100644 index 00000000..dc7c7e7a --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/RedefinedProperty.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <redefinedProperty /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.REDEFINED_PROPERTY, Namespace = "")] + public class RedefinedProperty + { + /// + /// xmi:idref attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.idRef, Namespace = XmiHelper.XmiNamespace)] + public virtual string? IdRef { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Specification.cs b/src/MTConnect.NET-SysML/Xmi/Specification.cs new file mode 100644 index 00000000..5f2c238c --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Specification.cs @@ -0,0 +1,26 @@ +using MTConnect.SysML.Xmi.UML; +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <specification /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.SPECIFICATION, Namespace = "")] + [XmlInclude(typeof(UmlOpaqueExpression))] + public class Specification : XmiElement + { + /// + /// body attribute + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.BODY, Namespace = "")] + public string? Body { get; set; } + + /// + /// language attribute + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.LANGUAGE, Namespace = "")] + public string? Language { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/SubsettedProperty.cs b/src/MTConnect.NET-SysML/Xmi/SubsettedProperty.cs new file mode 100644 index 00000000..b20443b5 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/SubsettedProperty.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <subsettedProperty /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.SUBSETTED_PROPERTY, Namespace = "")] + public class SubsettedProperty + { + /// + /// xmi:idref attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.idRef, Namespace = XmiHelper.XmiNamespace)] + public virtual string? IdRef { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/Type.cs b/src/MTConnect.NET-SysML/Xmi/Type.cs new file mode 100644 index 00000000..8a8617bd --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/Type.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <type /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.TYPE, Namespace = "")] + public class Type : XmiElement + { + /// + /// href attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.href, Namespace = "")] + public string? Href { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlAssociation.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlAssociation.cs new file mode 100644 index 00000000..ede529ab --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlAssociation.cs @@ -0,0 +1,20 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Association' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlAssociation : PackagedElement + { + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.MEMBER_END, Namespace = "")] + public MemberEnd[]? MemberEnds { get; set; } + + // TODO: Add + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlAssociationClass.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlAssociationClass.cs new file mode 100644 index 00000000..ff540836 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlAssociationClass.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:AssociationClass' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlAssociationClass : UmlClass + { + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.MEMBER_END, Namespace = "")] + public MemberEnd[]? MemberEnds { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlClass.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlClass.cs new file mode 100644 index 00000000..be097c64 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlClass.cs @@ -0,0 +1,45 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Class' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlClass : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.Class; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_ATTRIBUTE, Namespace = "")] + public UmlProperty[]? Properties { get; set; } + + /// + /// isAbstract attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.isAbstract, Namespace = "")] + public bool IsAbstract { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_RULE)] + public UmlConstraint[]? Constraints { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.GENERALIZATION, Namespace = "")] + public UmlGeneralization? Generalization { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlComment.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlComment.cs new file mode 100644 index 00000000..0e33a554 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlComment.cs @@ -0,0 +1,16 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Comment' + /// + [Serializable, XmlType(Namespace = XmiHelper.UmlNamespace), XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public class UmlComment : OwnedComment + { + /// + public override string Type => XmiHelper.UmlStructure.Comment; + + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlConstraint.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlConstraint.cs new file mode 100644 index 00000000..6ba3822d --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlConstraint.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Constraint' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_RULE, Namespace = "")] + public class UmlConstraint : OwnedRule + { + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.CONSTRAINED_ELEMENT, Namespace = "")] + public ConstrainedElement? ConstrainedElement { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlDataType.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlDataType.cs new file mode 100644 index 00000000..ecf441f9 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlDataType.cs @@ -0,0 +1,39 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:DataType' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlDataType : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.DataType; + + /// + /// isAbstract attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.isAbstract, Namespace = "")] + public bool IsAbstract { get; set; } + + /// + /// visibility attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.visibility, Namespace = "")] + public string Visibility { get; set; } = "public"; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.GENERALIZATION, Namespace = "")] + public UmlGeneralization[]? Generalization { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlEnumeration.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlEnumeration.cs new file mode 100644 index 00000000..f80640d6 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlEnumeration.cs @@ -0,0 +1,27 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Enumeration' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlEnumeration : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.Enumeration; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_LITERAL, Namespace = "")] + public UmlEnumerationLiteral[]? Items { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.GENERALIZATION, Namespace = "")] + public UmlGeneralization[]? Generalization { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlEnumerationLiteral.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlEnumerationLiteral.cs new file mode 100644 index 00000000..60ca0c5c --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlEnumerationLiteral.cs @@ -0,0 +1,21 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:EnumerationLiteral' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_LITERAL, Namespace = "")] + public class UmlEnumerationLiteral : OwnedLiteral + { + /// + public override string Type => XmiHelper.UmlStructure.EnumerationLiteral; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlExtension.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlExtension.cs new file mode 100644 index 00000000..2d78086e --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlExtension.cs @@ -0,0 +1,28 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Extension' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlExtension : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.Extension; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.MEMBER_END, Namespace = "")] + public MemberEnd[]? MemberEnds { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_END, Namespace = "")] + public UmlExtensionEnd? End { get; set; } + + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlExtensionEnd.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlExtensionEnd.cs new file mode 100644 index 00000000..7d32498d --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlExtensionEnd.cs @@ -0,0 +1,15 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:ExtensionEnd' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_END, Namespace = "")] + public class UmlExtensionEnd : OwnedEnd + { + /// + public override string Type => XmiHelper.UmlStructure.ExtensionEnd; + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlGeneralization.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlGeneralization.cs new file mode 100644 index 00000000..c8769745 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlGeneralization.cs @@ -0,0 +1,21 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Generalization' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.GENERALIZATION, Namespace = "")] + public class UmlGeneralization : Generalization + { + /// + public override string Type => XmiHelper.UmlStructure.Generalization; + + /// + /// general attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.GENERAL, Namespace = "")] + public string? General { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlInstanceValue.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlInstanceValue.cs new file mode 100644 index 00000000..91b03faf --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlInstanceValue.cs @@ -0,0 +1,21 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:InstanceValue' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.DEFAULT_VALUE, Namespace = "")] + public class UmlInstanceValue : DefaultValue + { + /// + public override string Type => XmiHelper.UmlStructure.InstanceValue; + + /// + /// instance attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.instance, Namespace = "")] + public string? Instance { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlLiteralString.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlLiteralString.cs new file mode 100644 index 00000000..dff4ca40 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlLiteralString.cs @@ -0,0 +1,21 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:LiteralString' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.DEFAULT_VALUE, Namespace = "")] + public class UmlLiteralString : DefaultValue + { + /// + public override string Type => XmiHelper.UmlStructure.LiteralString; + + /// + /// value attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.value, Namespace = "")] + public string? Value { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlModel.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlModel.cs new file mode 100644 index 00000000..996fab01 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlModel.cs @@ -0,0 +1,60 @@ +using System; +using System.Xml; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// uml:Model element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.MODEL, Namespace = XmiHelper.UmlNamespace)] + public class UmlModel : XmiElement + { + /// + public override string Type => XmiHelper.UmlStructure.Model; + + /// + /// Collection of + /// + [XmlElement(XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + + /// + /// Collection of + /// + [XmlElement(XmiHelper.XmiStructure.PACKAGE_IMPORT, Namespace = "")] + public UmlPackageImport[]? PackageImports { get; set; } + + /// + /// Represents <packagedElement /> element(s): + /// + /// <packagedElement xmi:type='uml:Profile' /> + /// <packagedElement xmi:type='uml:Package' /> + /// + /// + [XmlAnyElement(XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public XmlElement[]? PackagedElements { get; set; } + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _profiles; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Profiles => _profiles ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Profile); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _packages; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Packages => _packages ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Package); + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlOpaqueExpression.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlOpaqueExpression.cs new file mode 100644 index 00000000..7fc2c6bb --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlOpaqueExpression.cs @@ -0,0 +1,15 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:OpaqueExpression' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.SPECIFICATION, Namespace = "")] + public class UmlOpaqueExpression : Specification + { + /// + public override string Type => XmiHelper.UmlStructure.OpaqueExpression; + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlPackage.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlPackage.cs new file mode 100644 index 00000000..36f30241 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlPackage.cs @@ -0,0 +1,125 @@ +using System; +using System.Xml; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Package' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlPackage : PackagedElement + { + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + + /// + /// Represents <packagedElement /> element(s): + /// + /// <packagedElement xmi:type='uml:Enumeration' /> + /// <packagedElement xmi:type='uml:DataType' /> + /// <packagedElement xmi:type='uml:Class' /> + /// <packagedElement xmi:type='uml:Stereotype' /> + /// <packagedElement xmi:type='uml:Extension' /> + /// <packagedElement xmi:type='uml:Package' /> + /// <packagedElement xmi:type='uml:Association' /> + /// <packagedElement xmi:type='uml:AssociationClass' /> + /// + /// + [XmlAnyElement(XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public XmlElement[]? PackagedElements { get; set; } + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _extensions; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Extensions => _extensions ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Extension); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _stereotypes; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Stereotypes => _stereotypes ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Stereotype); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _classes; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Classes => _classes ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Class); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _enumerations; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Enumerations => _enumerations ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Enumeration); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _packages; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Packages => _packages ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Package); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _dataTypes; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection DataTypes => _dataTypes ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.DataType); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _associations; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Associations => _associations ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Association); + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _associationClasses; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection AssociationClasses => _associationClasses ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.AssociationClass); + //// TODO: Add xmi:Extension + + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlPackageImport.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlPackageImport.cs new file mode 100644 index 00000000..c7ee4afa --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlPackageImport.cs @@ -0,0 +1,21 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:PackageImport' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGE_IMPORT, Namespace = "")] + public class UmlPackageImport : PackageImport + { + /// + public override string Type => XmiHelper.UmlStructure.PackageImport; + + /// + /// importedPackage attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.importedPackage, Namespace = "")] + public string? ImportedPackage { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlPrimitiveType.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlPrimitiveType.cs new file mode 100644 index 00000000..391a53dd --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlPrimitiveType.cs @@ -0,0 +1,15 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:PrimitiveType' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlPrimitiveType : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.PrimitiveType; + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlProfile.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlProfile.cs new file mode 100644 index 00000000..d6488088 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlProfile.cs @@ -0,0 +1,56 @@ +using System; +using System.Xml; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Profile' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlProfile : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.Profile; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.PACKAGE_IMPORT, Namespace = "")] + public UmlPackageImport[]? Imports { get; set; } + + /// + /// Represents <packagedElement /> element(s): + /// + /// <packagedElement xmi:type='uml:Package' /> + /// + /// + [XmlAnyElement(XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public XmlElement[]? PackagedElements { get; set; } + + /// + /// Internal switch property for . + /// + [XmlIgnore] + private PackagedElementCollection? _packages; + /// + /// Collection of + /// + [XmlIgnore] + public PackagedElementCollection Packages => _packages ??= PackagedElementCollection.Deserialize(PackagedElements, XmiHelper.UmlStructure.Package); + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.METAMODEL_REFERENCE, Namespace = "")] + public MetamodelReference? MetaModelReference { get; set; } + + // TODO: Add appliedProfile + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlProperty.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlProperty.cs new file mode 100644 index 00000000..a481be9b --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlProperty.cs @@ -0,0 +1,136 @@ +using System; +using System.Xml; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Property' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.OWNED_ATTRIBUTE, Namespace = "")] + public class UmlProperty : OwnedAttribute + { + /// + public override string Type => XmiHelper.UmlStructure.Property; + + /// + /// association attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.association, Namespace = "")] + public string? Association { get; set; } + + // TODO: Lookup the uml:Association[@name] to determine the expected Property Name + // TODO: Figure out how to determine if the associated type is an array. Possibly just a reference to the lowerValue/upperValue elements + + /// + /// aggregation attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.aggregation, Namespace = "")] + public string? Aggregation { get; set; } + + /// + /// type attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.type, Namespace = "")] + public string? PropertyType { get; set; } + + /// + /// isStatic attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.isStatic, Namespace = "")] + public bool IsStatic { get; set; } + + /// + /// isReadOnly attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.isReadOnly, Namespace = "")] + public bool IsReadOnly { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.LOWER_VALUE, Namespace = "")] + public LowerValue? LowerValue { get; set; } + + /// + /// Child + /// + [XmlAnyElement(XmiHelper.XmiStructure.DEFAULT_VALUE, Namespace = "")] + public XmlElement? DefaultValueElement { get; set; } + private DefaultValue? _defaultValue; + public DefaultValue? DefaultValue + { + get + { + if (_defaultValue != null) + return _defaultValue; + if (DefaultValueElement == null) + return null; + + XmlRootAttribute xRoot = new XmlRootAttribute + { + ElementName = XmiHelper.XmiStructure.DEFAULT_VALUE, + IsNullable = true, + Namespace = "" + }; + + //XmlSerializer serial = new XmlSerializer(typeof(T), xRoot); + using var xReader = new XmlNodeReader(DefaultValueElement); + + XmlSerializer? serial = null; + string umlType = DefaultValueElement.GetAttribute(XmiHelper.XmiStructure.type, XmiHelper.XmiNamespace); + switch (umlType) + { + case XmiHelper.UmlStructure.InstanceValue: + serial = new XmlSerializer(typeof(UmlInstanceValue), xRoot); + break; + case XmiHelper.UmlStructure.LiteralString: + serial = new XmlSerializer(typeof(UmlLiteralString), xRoot); + break; + default: + break; + } + + if (serial != null) + { + object? deserializedObject = serial.Deserialize(xReader); + + if (deserializedObject != null) + { + switch (umlType) + { + case XmiHelper.UmlStructure.InstanceValue: + _defaultValue = deserializedObject as UmlInstanceValue; + break; + case XmiHelper.UmlStructure.LiteralString: + _defaultValue = deserializedObject as UmlLiteralString; + break; + default: + break; + } + } + } + + return _defaultValue; + } + } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.EXTENSION, Namespace = XmiHelper.XmiNamespace)] + public XmiExtension? Extension { get; set; } + + /// + /// visibility attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.visibility, Namespace = "")] + public string Visibility { get; set; } = "public"; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UML/UmlStereotype.cs b/src/MTConnect.NET-SysML/Xmi/UML/UmlStereotype.cs new file mode 100644 index 00000000..6ff0fcc3 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UML/UmlStereotype.cs @@ -0,0 +1,27 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi.UML +{ + /// + /// where xmi:type='uml:Stereotype' + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public class UmlStereotype : PackagedElement + { + /// + public override string Type => XmiHelper.UmlStructure.Stereotype; + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.OWNED_COMMENT, Namespace = "")] + public UmlComment[]? Comments { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.PACKAGED_ELEMENT, Namespace = "")] + public UmlProperty[]? Properties { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/UpperValue.cs b/src/MTConnect.NET-SysML/Xmi/UpperValue.cs new file mode 100644 index 00000000..53912852 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/UpperValue.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <upperValue /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.UPPER_VALUE, Namespace = "")] + public class UpperValue : XmiElement + { + /// + /// value attribute + /// + [XmlAttribute(XmiHelper.XmiStructure.value, Namespace = "")] + public string? Value { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiDeserializer.cs b/src/MTConnect.NET-SysML/Xmi/XmiDeserializer.cs new file mode 100644 index 00000000..02246cd5 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiDeserializer.cs @@ -0,0 +1,92 @@ +using System.Threading; +using System.Xml; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// A class that can deserialize a XMI document into an object-oriented form. + /// + public sealed class XmiDeserializer + { + private XmlDocument xDoc; + private XmlNamespaceManager nsmgr; + + /// + /// Constructs a new instance of the deserializer with a reference to the source document. + /// + /// A source of XMI to deserialize + /// + public XmiDeserializer(XmlDocument xmlDocument) + { + xDoc = xmlDocument; + nsmgr = new XmlNamespaceManager(xDoc.NameTable); + nsmgr.AddNamespace("xmi", XmiHelper.XmiNamespace); + nsmgr.AddNamespace("uml", XmiHelper.UmlNamespace); + nsmgr.AddNamespace("Profile", XmiHelper.ProfileNamespace); + nsmgr.AddNamespace("StandardProfile", XmiHelper.StandardProfileNamespace); + nsmgr.AddNamespace("Validation_Profile", XmiHelper.Validation_ProfileNamespace); + nsmgr.AddNamespace("Dependency_Matrix_Profile", XmiHelper.Dependency_Matrix_ProfileNamespace); + nsmgr.AddNamespace("Concept_Modeling_Profile", XmiHelper.Concept_Modeling_ProfileNamespace); + nsmgr.AddNamespace("DSL_Customization", XmiHelper.DSL_CustomizationNamespace); + nsmgr.AddNamespace("sysml", XmiHelper.SysMlNamespace); + nsmgr.AddNamespace("MagicDraw_Profile", XmiHelper.MagicDraw_ProfileNamespace); + nsmgr.AddNamespace("CCM_Internal_Implementation_Profile", XmiHelper.Ccm_Internal_Implementation_ProfileNamespace); + nsmgr.AddNamespace("MD_Customization_for_SysML__additional_stereotypes", XmiHelper.Md_Customization_for_SysML__additional_stereotypesNamespace); + nsmgr.AddNamespace("SimulationProfile", XmiHelper.SimulationProfileNamespace); + } + + /// + /// Deserializes the XML Document into the specified type. + /// + /// The deserialized object as a . + public XmiDocument? Deserialize(CancellationToken cancellationToken) + { + XmiDocument? result = null; + + XmlRootAttribute xRoot = new XmlRootAttribute(); + xRoot.ElementName = xDoc.DocumentElement.LocalName; + xRoot.IsNullable = true; + xRoot.Namespace = XmiHelper.XmiNamespace; + XmlSerializer serial = new XmlSerializer(typeof(Xmi.XmiDocument), xRoot); + // Deserialize the XmlNode + using (XmlNodeReader xReader = new XmlNodeReader(xDoc.DocumentElement)) + { + object? deserializedObject = serial.Deserialize(xReader); + + result = deserializedObject as XmiDocument; + + } + + return result; + } + + /// + /// Creates a from a reference to the filepath of a XMI document. + /// + /// Filepath to a XMI-formatted XML document. + /// + /// + public static XmiDeserializer FromFile(string filename) + { + var xDoc = new XmlDocument(); + xDoc.Load(filename); + + return new XmiDeserializer(xDoc); + } + + /// + /// Creates a from raw XML. + /// + /// Raw XML string + /// + /// + public static XmiDeserializer FromXml(string xml) + { + var xDoc = new XmlDocument(); + xDoc.LoadXml(xml); + + return new XmiDeserializer(xDoc); + } + } +} diff --git a/src/MTConnect.NET-SysML/Xmi/XmiDocument.cs b/src/MTConnect.NET-SysML/Xmi/XmiDocument.cs new file mode 100644 index 00000000..844ce43b --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiDocument.cs @@ -0,0 +1,37 @@ +using MTConnect.SysML.Xmi.Profile; +using MTConnect.SysML.Xmi.UML; +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// xmi:XMI element + /// + [Serializable, XmlRoot(ElementName = "XMI", Namespace = XmiHelper.XmiNamespace)] + public class XmiDocument + { + /// + /// Child + /// + public XmiDocumentation? Documentation { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.MODEL, Namespace = XmiHelper.UmlNamespace)] + public UmlModel? Model { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.ProfileStructure.NORMATIVE, Namespace = XmiHelper.ProfileNamespace)] + public Normative[]? NormativeIntroductions { get; set; } + + /// + /// Collection of + /// + [XmlElement(ElementName = XmiHelper.ProfileStructure.DEPRECATED, Namespace = XmiHelper.ProfileNamespace)] + public Deprecated[]? Deprecations { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiDocumentation.cs b/src/MTConnect.NET-SysML/Xmi/XmiDocumentation.cs new file mode 100644 index 00000000..420d993f --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiDocumentation.cs @@ -0,0 +1,24 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <xmi:Documentation /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.DOCUMENTATION, Namespace = XmiHelper.XmiNamespace)] + public class XmiDocumentation + { + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.EXPORTER, Namespace = XmiHelper.XmiNamespace)] + public XmiExporter? Exporter { get; set; } + + /// + /// Child + /// + [XmlElement(ElementName = XmiHelper.XmiStructure.EXPORTER_VERSION, Namespace = XmiHelper.XmiNamespace)] + public XmiExporterVersion? ExporterVersion { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiElement.cs b/src/MTConnect.NET-SysML/Xmi/XmiElement.cs new file mode 100644 index 00000000..6dd521cb --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiElement.cs @@ -0,0 +1,28 @@ +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// Abstract model for common xmi elements + /// + public abstract class XmiElement : IXmiElement + { + /// + /// xmi:id attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.id, Namespace = XmiHelper.XmiNamespace)] + public virtual string? Id { get; set; } + + /// + /// name attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.name, Namespace = "")] + public virtual string? Name { get; set; } + + /// + /// xmi:type attribute + /// + [XmlAttribute(AttributeName = XmiHelper.XmiStructure.type, Namespace = XmiHelper.XmiNamespace)] + public virtual string? Type { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiExporter.cs b/src/MTConnect.NET-SysML/Xmi/XmiExporter.cs new file mode 100644 index 00000000..80a472d6 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiExporter.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <xmi:exporter /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.EXPORTER, Namespace = XmiHelper.XmiNamespace)] + public class XmiExporter + { + /// + /// value of the element + /// + [XmlText] + public string? Value { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiExporterVersion.cs b/src/MTConnect.NET-SysML/Xmi/XmiExporterVersion.cs new file mode 100644 index 00000000..b4346181 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiExporterVersion.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <xmi:exporterVersion /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.EXPORTER_VERSION, Namespace = XmiHelper.XmiNamespace)] + public class XmiExporterVersion + { + /// + /// value of the element + /// + [XmlText] + public string? Value { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiExtension.cs b/src/MTConnect.NET-SysML/Xmi/XmiExtension.cs new file mode 100644 index 00000000..5fd048a2 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiExtension.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace MTConnect.SysML.Xmi +{ + /// + /// <xmi:Extension /> element + /// + [Serializable, XmlRoot(ElementName = XmiHelper.XmiStructure.EXTENSION, Namespace = XmiHelper.XmiNamespace)] + public class XmiExtension : XmiElement + { + /// + /// extender attribute + /// + [XmlAttribute(XmiHelper.XmiStructure.extender, Namespace = "")] + public string? Extender { get; set; } + } +} \ No newline at end of file diff --git a/src/MTConnect.NET-SysML/Xmi/XmiHelper.cs b/src/MTConnect.NET-SysML/Xmi/XmiHelper.cs new file mode 100644 index 00000000..ecff87a3 --- /dev/null +++ b/src/MTConnect.NET-SysML/Xmi/XmiHelper.cs @@ -0,0 +1,184 @@ +namespace MTConnect.SysML.Xmi +{ + internal static class XmiHelper + { + public const string XmiNamespace = "http://www.omg.org/spec/XMI/20131001"; + public const string UmlNamespace = "http://www.omg.org/spec/UML/20131001"; + public const string ProfileNamespace = "http://www.magicdraw.com/schemas/Profile.xmi"; + public const string StandardProfileNamespace = "http://www.omg.org/spec/UML/20131001/StandardProfile"; + public const string Validation_ProfileNamespace = "http://www.magicdraw.com/schemas/Validation_Profile.xmi"; + public const string Dependency_Matrix_ProfileNamespace = "http://www.magicdraw.com/schemas/Dependency_Matrix_Profile.xmi"; + public const string Concept_Modeling_ProfileNamespace = "http://www.magicdraw.com/schemas/Concept_Modeling_Profile.xmi"; + public const string DSL_CustomizationNamespace = "http://www.magicdraw.com/schemas/DSL_Customization.xmi"; + public const string SysMlNamespace = "http://www.omg.org/spec/SysML/20150709/SysML"; + public const string MagicDraw_ProfileNamespace = "http://www.omg.org/spec/UML/20131001/MagicDrawProfile"; + public const string Ccm_Internal_Implementation_ProfileNamespace = "http://www.magicdraw.com/schemas/CCM_Internal_Implementation_Profile.xmi"; + public const string Md_Customization_for_SysML__additional_stereotypesNamespace = "http://www.magicdraw.com/spec/Customization/180/SysML"; + public const string SimulationProfileNamespace = "http://www.magicdraw.com/schemas/SimulationProfile.xmi"; + + public static class ProfileStructure + { + #region XML Tags + public const string NORMATIVE = "normative"; + public const string DEPRECATED = "deprecated"; + public const string EXTENSIBLE = "extensible"; + public const string INFORMATIVE = "informative"; + public const string OBSERVES = "observes"; + public const string ORGANIZER = "organizer"; + public const string VALUE_TYPE = "valueType"; + #endregion + } + + public static class XmiStructure + { + #region XML Tags + public const string PACKAGED_ELEMENT = "packagedElement"; + public const string PACKAGE_IMPORT = "packageImport"; + public const string OWNED_COMMENT = "ownedComment"; + public const string OWNED_END = "ownedEnd"; + public const string OWNED_LITERAL = "ownedLiteral"; + public const string OWNED_RULE = "ownedRule"; + public const string OWNED_ATTRIBUTE = "ownedAttribute"; + public const string OWNED_OPERATION = "ownedOperation"; + public const string OWNED_PARAMETER = "ownedParameter"; + public const string BODY = "body"; + public const string SPECIFICATION = "specification"; + public const string LANGUAGE = "language"; + public const string GENERALIZATION = "generalization"; + public const string GENERAL = "general"; + public const string TYPE = "type"; + public const string ASSOCIATION = "association"; + public const string DEFAULT_VALUE = "defaultValue"; + public const string REDEFINED_PROPERTY = "redefinedProperty"; + public const string SUBSETTED_PROPERTY = "subsettedProperty"; + public const string MODEL = "Model"; + public const string ANNOTATED_ELEMENT = "annotatedElement"; + public const string LOWER_VALUE = "lowerValue"; + public const string UPPER_VALUE = "upperValue"; + public const string EXTENSION = "Extension"; + public const string MODEL_EXTENSION = "modelExtension"; + public const string CONSTRAINED_ELEMENT = "constrainedElement"; + public const string MEMBER_END = "memberEnd"; + public const string METAMODEL_REFERENCE = "metamodelReference"; + public const string DOCUMENTATION = "Documentation"; + public const string EXPORTER = "exporter"; + public const string EXPORTER_VERSION = "exporterVersion"; + #endregion + + #region XML Attributes + public const string visibility = "visibility"; + public const string isQuery = "isQuery"; + public const string isAbstract = "isAbstract"; + public const string aggregation = "aggregation"; + public const string id = "id"; + public const string idRef = "idref"; + public const string type = "type"; + public const string name = "name"; + public const string version = "version"; + public const string baseElement = "base_Element"; + public const string baseClass = "base_Class"; + public const string baseComment = "base_Comment"; + public const string baseEnumeration = "base_Enumeration"; + public const string baseAssociation = "base_Association"; + public const string importedPackage = "importedPackage"; + public const string href = "href"; + public const string association = "association"; + public const string instance = "instance"; + public const string isStatic = "isStatic"; + public const string isReadOnly = "isReadOnly"; + public const string value = "value"; + public const string extender = "extender"; + #endregion + } + + public class UmlStructure + { + #region UML xmi:type options + /// + /// <packagedElement xmi:type='uml:Enumeration' /> + /// + public const string Enumeration = "uml:Enumeration"; + /// + /// <packagedElement xmi:type='uml:DataType' /> + /// + public const string DataType = "uml:DataType"; + /// + /// <packagedElement xmi:type='uml:Class' /> + /// + public const string Class = "uml:Class"; + /// + /// <packagedElement xmi:type='uml:Stereotype' /> + /// + public const string Stereotype = "uml:Stereotype"; + /// + /// <packagedElement xmi:type='uml:Extension' /> + /// + public const string Extension = "uml:Extension"; + /// + /// <packagedElement xmi:type='uml:Package' /> + /// + public const string Package = "uml:Package"; + /// + /// <ownedComment xmi:type='uml:Comment' /> + /// + public const string Comment = "uml:Comment"; + /// + /// <ownedRule xmi:type='uml:Constraint' /> + /// + public const string Constraint = "uml:Constraint"; + /// + /// <ownedLiteral xmi:type='uml:EnumerationLiteral' /> + /// + public const string EnumerationLiteral = "uml:EnumerationLiteral"; + /// + /// <ownedEnd xmi:type='uml:ExtensionEnd' /> + /// + public const string ExtensionEnd = "uml:ExtensionEnd"; + /// + /// <generalization xmi:type='uml:Generalization' /> + /// + public const string Generalization = "uml:Generalization"; + /// + /// <defaultValue xmi:type='uml:InstanceValue' /> + /// + public const string InstanceValue = "uml:InstanceValue"; + /// + /// <defaultValue xmi:type='uml:LiteralString' /> + /// + public const string LiteralString = "uml:LiteralString"; + /// + /// <uml:Model xmi:type='uml:Model' /> + /// + public const string Model = "uml:Model"; + /// + /// <specification xmi:type='uml:OpaqueExpression' /> + /// + public const string OpaqueExpression = "uml:OpaqueExpression"; + /// + /// <packageImport xmi:type='uml:PackageImport' /> + /// + public const string PackageImport = "uml:PackageImport"; + /// + /// <packagedElement xmi:type='uml:PrimitiveType' /> + /// + public const string PrimitiveType = "uml:PrimitiveType"; + /// + /// <packagedElement xmi:type='uml:Profile' /> + /// + public const string Profile = "uml:Profile"; + /// + /// <ownedAttribute xmi:type='uml:Property' /> + /// + public const string Property = "uml:Property"; + /// + /// <ownedAttribute xmi:type='uml:AssociationClass' /> + /// + public const string AssociationClass = "uml:AssociationClass"; + /// + /// <ownedAttribute xmi:type='uml:Association' /> + /// + public const string Association = "uml:Association"; + #endregion + } + } +} diff --git a/src/MTConnect.NET.sln b/src/MTConnect.NET.sln index 60f82171..9b019e69 100644 --- a/src/MTConnect.NET.sln +++ b/src/MTConnect.NET.sln @@ -103,6 +103,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MTConnect-Agent-MQTT-Relay- EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MTConnect.NET-TLS", "MTConnect.NET-TLS\MTConnect.NET-TLS.csproj", "{82B8CF89-A378-47FF-B0DE-EE5F020D9586}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTConnect.NET-SysML", "MTConnect.NET-SysML\MTConnect.NET-SysML.csproj", "{30D59D35-96E8-4E41-B8F7-D1B211DFC360}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -314,6 +316,12 @@ Global {82B8CF89-A378-47FF-B0DE-EE5F020D9586}.Package|Any CPU.Build.0 = Debug|Any CPU {82B8CF89-A378-47FF-B0DE-EE5F020D9586}.Release|Any CPU.ActiveCfg = Release|Any CPU {82B8CF89-A378-47FF-B0DE-EE5F020D9586}.Release|Any CPU.Build.0 = Release|Any CPU + {30D59D35-96E8-4E41-B8F7-D1B211DFC360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30D59D35-96E8-4E41-B8F7-D1B211DFC360}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30D59D35-96E8-4E41-B8F7-D1B211DFC360}.Package|Any CPU.ActiveCfg = Debug|Any CPU + {30D59D35-96E8-4E41-B8F7-D1B211DFC360}.Package|Any CPU.Build.0 = Debug|Any CPU + {30D59D35-96E8-4E41-B8F7-D1B211DFC360}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30D59D35-96E8-4E41-B8F7-D1B211DFC360}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE