diff --git a/SemanticData/Tests/USNodeSetValidationUnitTestProject/UANodeContextUnitTest.cs b/SemanticData/Tests/USNodeSetValidationUnitTestProject/UANodeContextUnitTest.cs index 091a3b88..c45dc903 100644 --- a/SemanticData/Tests/USNodeSetValidationUnitTestProject/UANodeContextUnitTest.cs +++ b/SemanticData/Tests/USNodeSetValidationUnitTestProject/UANodeContextUnitTest.cs @@ -1,9 +1,9 @@ -//___________________________________________________________________________________ +//__________________________________________________________________________________________________ // -// Copyright (C) 2021, Mariusz Postol LODZ POLAND. +// Copyright (C) 2022, Mariusz Postol LODZ POLAND. // -// To be in touch join the community at GITTER: https://gitter.im/mpostol/OPC-UA-OOI -//___________________________________________________________________________________ +// To be in touch join the community at GitHub: https://github.com/mpostol/OPC-UA-OOI/discussions +//__________________________________________________________________________________________________ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -195,8 +195,9 @@ public void CalculateNodeReferencesNullArguments() Mock _validatorMoc = new Mock(); List _traceBuffer = new List(); IUANodeBase _first = new UANodeContext(NodeId.Parse("ns=1;i=11"), _addressSpaceMock.Object, x => _traceBuffer.Add(x)); - Assert.ThrowsException(() => _first.CalculateNodeReferences(null, _validatorMoc.Object)); - Assert.ThrowsException(() => _first.CalculateNodeReferences(_mockNodeFactory.Object, null)); + Assert.ThrowsException(() => _first.CalculateNodeReferences(null, _validatorMoc.Object, y => { })); + Assert.ThrowsException(() => _first.CalculateNodeReferences(_mockNodeFactory.Object, null, y => { })); + Assert.ThrowsException(() => _first.CalculateNodeReferences(_mockNodeFactory.Object, _validatorMoc.Object, null)); } [TestMethod] @@ -233,14 +234,17 @@ public void CalculateNodeReferencesNullUANodeTest() Mock _mockNodeFactory = new Mock(); _mockNodeFactory.Setup(x => x.NewReference()).Returns(referenceFactoryMock.Object); Mock _validatorMoc = new Mock(); - _validatorMoc.Setup(x => x.ValidateExportNode(It.IsAny(), _mockNodeFactory.Object, It.IsAny())); + _validatorMoc.Setup(x => x.ValidateExportNode(It.IsAny(), _mockNodeFactory.Object, It.IsAny>(), It.IsAny())); //testing - ((IUANodeBase)node2Test).CalculateNodeReferences(_mockNodeFactory.Object, _validatorMoc.Object); + int counter = 0; + ((IUANodeBase)node2Test).CalculateNodeReferences(_mockNodeFactory.Object, _validatorMoc.Object, y => counter++); + //validation + Assert.AreEqual(1, counter); addressSpaceMock.Verify(x => x.GetMyReferences(It.IsAny()), Times.Once); addressSpaceMock.Verify(x => x.ExportBrowseName(It.IsAny(), It.IsAny()), Times.Once); - _validatorMoc.Verify(x => x.ValidateExportNode(It.IsAny(), _mockNodeFactory.Object, It.IsAny()), Times.Never); + _validatorMoc.Verify(x => x.ValidateExportNode(It.Is(z => z == targetMock.Object), _mockNodeFactory.Object, It.IsAny>(), It.Is(y => y == listOfReferences[0])), Times.Never); Assert.AreEqual(0, _traceBuffer.Count, _traceBuffer.Count == 0 ? "" : _traceBuffer[0].Message); } diff --git a/SemanticData/Tests/USNodeSetValidationUnitTestProject/ValidatorUnitTest.cs b/SemanticData/Tests/USNodeSetValidationUnitTestProject/ValidatorUnitTest.cs index 2a9d4179..84b357a6 100644 --- a/SemanticData/Tests/USNodeSetValidationUnitTestProject/ValidatorUnitTest.cs +++ b/SemanticData/Tests/USNodeSetValidationUnitTestProject/ValidatorUnitTest.cs @@ -1,6 +1,6 @@ //__________________________________________________________________________________________________ // -// Copyright (C) 2021, Mariusz Postol LODZ POLAND. +// Copyright (C) 2022, Mariusz Postol LODZ POLAND. // // To be in touch join the community at GitHub: https://github.com/mpostol/OPC-UA-OOI/discussions //__________________________________________________________________________________________________ @@ -56,7 +56,7 @@ public void UAMethodTest() DisplayName = new LocalizedText[] { new LocalizedText() { Value = "Start" } }, References = new Reference[] { } }; - List traceBuffer = new List(); + List traceBuffer = new List(); UANodeContext nodeContext = new UANodeContext(DataSerialization.NodeId.Parse(method.NodeId), addressSpaceBuildContextMock.Object, x => traceBuffer.Add(x)); nodeContext.Update(method, x => { }); Mock nodeContainerMock = new Mock(); @@ -64,7 +64,7 @@ public void UAMethodTest() nodeContainerMock.Setup(x => x.AddNodeFactory()).Returns(methodInstanceFactory.Object); //TODO UANodeSetValidation.Extensions.GetObject - object reference not set #624 Assert.Inconclusive("UANodeSetValidation.Extensions.GetObject - object reference not set #624"); - _i2t.ValidateExportNode(nodeContext, nodeContainerMock.Object); + _i2t.ValidateExportNode(nodeContext, nodeContainerMock.Object, z => { }); Assert.AreEqual(0, traceBuffer.Count); } } diff --git a/SemanticData/UANodeSetValidation/AddressSpaceContext.cs b/SemanticData/UANodeSetValidation/AddressSpaceContext.cs index 0efcd3ce..34d727ef 100644 --- a/SemanticData/UANodeSetValidation/AddressSpaceContext.cs +++ b/SemanticData/UANodeSetValidation/AddressSpaceContext.cs @@ -312,16 +312,17 @@ private IUANodeContext TryGetUANodeContext(NodeId nodeId) return _ret; } + //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 private void ValidateAndExportModel(int nameSpaceIndex) { IValidator validator = new Validator(this, m_TraceEvent); - IEnumerable stubs = from _key in m_NodesDictionary.Values where _key.NodeIdContext.NamespaceIndex == nameSpaceIndex select _key; - IEnumerable undefindNodes = from node in stubs - where Object.ReferenceEquals(node.UANode, null) - select node; - foreach (IUANodeContext item in undefindNodes) + IEnumerable stubs = from _key in m_NodesDictionary.Values where _key.NodeIdContext.NamespaceIndex == nameSpaceIndex select _key; + IEnumerable undefindNodes = from node in stubs + where Object.ReferenceEquals(node.UANode, null) + select node; + foreach (IUANodeBase item in undefindNodes) m_TraceEvent.WriteTraceMessage(TraceMessage.BuildErrorTraceMessage(BuildError.NodeCannotBeNull, $"the node {item.ToString()} is not defined in the UANodeSet model")); - List nodes = (from _node in stubs where _node.UANode != null && (_node.UANode is UAType) select _node).ToList(); + List nodes = (from _node in stubs where _node.UANode != null && (_node.UANode is UAType) select _node).ToList(); m_TraceEvent.TraceData(TraceEventType.Verbose, 938023414, $"Selected {nodes.Count} types to be validated."); IUANodeBase _objects = TryGetUANodeContext(UAInformationModel.ObjectIds.ObjectsFolder); if (_objects is null) @@ -338,18 +339,24 @@ where Object.ReferenceEquals(node.UANode, null) string _version = modelTableEntry.Version; InformationModelFactory.CreateNamespace(modelTableEntry.ModelUri.ToString(), _publicationDate, _version); } - foreach (IUANodeBase item in nodes) + //NetworkIdentifier is missing in generated Model Design for DI model #629 + do { - try - { - validator.ValidateExportNode(item, InformationModelFactory); - } - catch (Exception ex) + NodesCollection embededNodes = new NodesCollection(); + foreach (IUANodeBase item in nodes) { - string msg = string.Format("Error caught while processing the node {0}. The message: {1} at {2}.", item.UANode.NodeId, ex.Message, ex.StackTrace); - m_TraceEvent.WriteTraceMessage(TraceMessage.BuildErrorTraceMessage(BuildError.NonCategorized, msg)); + try + { + validator.ValidateExportNode(item, InformationModelFactory, y => { if (y.NodeIdContext.NamespaceIndex == nameSpaceIndex) embededNodes.AddOrReplace(y, false); }); + } + catch (Exception ex) + { + string msg = string.Format("Error caught while processing the node {0}. The message: {1} at {2}.", item.UANode.NodeId, ex.Message, ex.StackTrace); + m_TraceEvent.WriteTraceMessage(TraceMessage.BuildErrorTraceMessage(BuildError.NonCategorized, msg)); + } } - } + nodes = embededNodes.ToList(); + } while (nodes.Count > 0); string message = null; if (m_TraceEvent.Errors == 0) { diff --git a/SemanticData/UANodeSetValidation/IUANodeBase.cs b/SemanticData/UANodeSetValidation/IUANodeBase.cs index c1e7aaba..753e38f8 100644 --- a/SemanticData/UANodeSetValidation/IUANodeBase.cs +++ b/SemanticData/UANodeSetValidation/IUANodeBase.cs @@ -1,12 +1,11 @@ -//___________________________________________________________________________________ +//__________________________________________________________________________________________________ // -// Copyright (C) 2021, Mariusz Postol LODZ POLAND. +// Copyright (C) 2022, Mariusz Postol LODZ POLAND. // -// To be in touch join the community at GITTER: https://gitter.im/mpostol/OPC-UA-OOI -//___________________________________________________________________________________ +// To be in touch join the community at GitHub: https://github.com/mpostol/OPC-UA-OOI/discussions +//__________________________________________________________________________________________________ using System; -using System.Collections.Generic; using System.Xml; using UAOOI.SemanticData.InformationModelFactory; using UAOOI.SemanticData.UANodeSetValidation.DataSerialization; @@ -14,63 +13,72 @@ namespace UAOOI.SemanticData.UANodeSetValidation { - /// /// Interface IUANodeBase - if implemented captures all basic information represented by the UA Node /// - internal interface IUANodeBase: IEquatable + internal interface IUANodeBase : IEquatable { - /// /// Calculates the node references. /// /// The node factory. /// The validator. - void CalculateNodeReferences(INodeFactory nodeFactory, IValidator validator); + /// It creates the node at the top level of the model. Called if the node has reference to another node that cannot be defined as a child. + void CalculateNodeReferences(INodeFactory nodeFactory, IValidator validator, Action validateExportNode2Model); + /// /// Gets the node identifier. /// /// The imported node identifier. NodeId NodeIdContext { get; } + /// /// Gets the wrapped node described by the type. /// UANode UANode { get; } + /// /// Exports the browse name of the wrapped node by this instance. /// /// An instance of representing the browse name of the node. XmlQualifiedName ExportNodeBrowseName(); + /// /// Gets a value indicating whether this instance is a property. /// /// true if this instance is property; otherwise, false. bool IsProperty { get; } + /// /// Gets a value indicating whether this instance is property variable type. /// /// true if this instance is property variable type; otherwise, false. bool IsPropertyVariableType { get; } + /// /// Exports the browse name of this node recognized as or target. /// /// The trace event. /// An instance of representing subtype or type of an instance. XmlQualifiedName ExportBrowseNameBaseType(Action traceEvent); + /// /// Gets the derived instances. /// - Dictionary GetDerivedInstances(); + NodesCollection GetDerivedInstances(); + /// /// Exports the BrowseName of the BaseType. /// /// An instance of representing the base type.. XmlQualifiedName ExportBaseTypeBrowseName(); + /// /// Gets the modeling rule associated with this node. /// /// The associated with the node. Null if valid modeling rule cannot be recognized. ModelingRules? ModelingRule { get; } + /// /// Removes the inherited values. /// @@ -79,6 +87,5 @@ internal interface IUANodeBase: IEquatable /// If a member is overridden all inherited values of the node attributes must be removed. /// void RemoveInheritedValues(IUANodeBase instanceDeclaration); - } -} +} \ No newline at end of file diff --git a/SemanticData/UANodeSetValidation/IValidator.cs b/SemanticData/UANodeSetValidation/IValidator.cs index e1202943..1d78aa1f 100644 --- a/SemanticData/UANodeSetValidation/IValidator.cs +++ b/SemanticData/UANodeSetValidation/IValidator.cs @@ -1,10 +1,11 @@ -//___________________________________________________________________________________ +//__________________________________________________________________________________________________ // -// Copyright (C) 2021, Mariusz Postol LODZ POLAND. +// Copyright (C) 2022, Mariusz Postol LODZ POLAND. // -// To be in touch join the community at GITTER: https://gitter.im/mpostol/OPC-UA-OOI -//___________________________________________________________________________________ +// To be in touch join the community at GitHub: https://github.com/mpostol/OPC-UA-OOI/discussions +//__________________________________________________________________________________________________ +using System; using UAOOI.SemanticData.InformationModelFactory; namespace UAOOI.SemanticData.UANodeSetValidation @@ -20,13 +21,15 @@ internal interface IValidator /// The node context to be validated and exported. /// A model export factory. /// The reference to parent node. - void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory, UAReferenceContext parentReference); + /// It creates the node at the top level of the model. Called if the node has reference to another node that cannot be defined as a child. + void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory, Action validateExportNode2Model, UAReferenceContext parentReference); /// /// Validates and exports it using an object of type. /// /// The node context to be validated and exported. /// A model export factory. - void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory); + /// It creates the node at the top level of the model. Called if the node has reference to another node that cannot be defined as a child. + void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory, Action validateExportNode2Model); } } \ No newline at end of file diff --git a/SemanticData/UANodeSetValidation/ReferenceKindEnum.cs b/SemanticData/UANodeSetValidation/ReferenceKindEnum.cs index 2eaa51c0..b395c8cc 100644 --- a/SemanticData/UANodeSetValidation/ReferenceKindEnum.cs +++ b/SemanticData/UANodeSetValidation/ReferenceKindEnum.cs @@ -1,11 +1,10 @@ //__________________________________________________________________________________________________ // -// Copyright (C) 2021, Mariusz Postol LODZ POLAND. +// Copyright (C) 2022, Mariusz Postol LODZ POLAND. // // To be in touch join the community at GitHub: https://github.com/mpostol/OPC-UA-OOI/discussions //__________________________________________________________________________________________________ - namespace UAOOI.SemanticData.UANodeSetValidation { /// @@ -33,11 +32,6 @@ internal enum ReferenceKindEnum /// HasTypeDefinition, - /// - /// The HierarchicalReferences - /// - HierarchicalReferences, - /// /// The HasSubtype /// diff --git a/SemanticData/UANodeSetValidation/UANodeContext.cs b/SemanticData/UANodeSetValidation/UANodeContext.cs index ee3def26..3afc8133 100644 --- a/SemanticData/UANodeSetValidation/UANodeContext.cs +++ b/SemanticData/UANodeSetValidation/UANodeContext.cs @@ -47,6 +47,7 @@ internal UANodeContext(NodeId nodeId, IAddressSpaceBuildContext addressSpaceCont /// Builds the symbolic identifier. /// /// The browse path. + //NetworkIdentifier is missing in generated Model Design for DI model #629 public void BuildSymbolicId(List path) { if (this.UANode == null) @@ -95,8 +96,6 @@ public void Update(UANode node, Action addReference) case ReferenceKindEnum.Custom: case ReferenceKindEnum.HasComponent: case ReferenceKindEnum.HasProperty: - //NetworkIdentifier is missing in generated Model Design for DI model #629 - case ReferenceKindEnum.HierarchicalReferences: break; case ReferenceKindEnum.HasModellingRule: @@ -134,18 +133,20 @@ public XmlQualifiedName ExportNodeBrowseName() } /// - /// Processes the node references to calculate all relevant properties. Must be called after finishing import of all the parent models. + /// Calculates the node references. /// - /// The node container. + /// The node factory. /// The validator. - /// must not be null. + /// It creates the node at the top level of the model. Called if the node has reference to another node that cannot be defined as a child. //TODO Import simple NodeSet2 file is incomplete #510 - void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator validator) + void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator validator, Action validateExportNode2Model) { if (nodeFactory == null) throw new ArgumentNullException(nameof(nodeFactory), $"{nodeFactory} must not be null in {nameof(IUANodeBase.CalculateNodeReferences)}"); if (validator is null) throw new ArgumentNullException(nameof(validator), $"{nameof(validator)} must not be null in {nameof(IUANodeBase.CalculateNodeReferences)}"); + if (validateExportNode2Model == null) + throw new ArgumentNullException(nameof(validateExportNode2Model), $"The parameter must not be null in {nameof(IUANodeBase.CalculateNodeReferences)}"); List _children = new List(); foreach (UAReferenceContext _rfx in m_AddressSpaceContext.GetMyReferences(this)) { @@ -157,7 +158,6 @@ void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator va switch (_rfx.ReferenceKind) { case ReferenceKindEnum.Custom: - //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 XmlQualifiedName _ReferenceType = _rfx.GetReferenceTypeName(); if (_ReferenceType == XmlQualifiedName.Empty) { @@ -172,8 +172,8 @@ void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator va IReferenceFactory _or = nodeFactory.NewReference(); _or.IsInverse = !_rfx.IsForward; _or.ReferenceType = _ReferenceType; + //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 _or.TargetId = _rfx.BrowsePath(); - //switch (_rfx.TargetNode.UANode.NodeClassEnum) switch (_rfx.TargetNode.UANode.NodeClassEnum) { case NodeClassEnum.UADataType: @@ -181,20 +181,32 @@ void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator va case NodeClassEnum.UAReferenceType: case NodeClassEnum.UAVariableType: break; + case NodeClassEnum.UAMethod: + _TraceEvent(TraceMessage.DiagnosticTraceMessage($"Removed the graph of nodes at {_rfx.TargetNode} from the model")); //validator..ValidateExportNode(_rc.TargetNode, nodeFactory, _rc); break; + case NodeClassEnum.UAObject: + validateExportNode2Model(_rfx.TargetNode); + //validator.ValidateExportNode(_rfx.TargetNode, nodeFactory, _rfx); break; + + //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 case NodeClassEnum.UAVariable: + _TraceEvent(TraceMessage.DiagnosticTraceMessage($"Removed the graph of nodes at {_rfx.TargetNode} from the model")); break; + case NodeClassEnum.UAView: + _TraceEvent(TraceMessage.DiagnosticTraceMessage($"Removed the graph of nodes at {_rfx.TargetNode} from the model")); break; - case NodeClassEnum.Unknown: + case NodeClassEnum.Unknown: + _TraceEvent(TraceMessage.DiagnosticTraceMessage($"Removed the graph of nodes at {_rfx.TargetNode} from the model")); break; + default: - break; + throw new ArgumentOutOfRangeException(nameof(_rfx.TargetNode.UANode.NodeClassEnum)); } break; @@ -215,14 +227,6 @@ void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator va case ReferenceKindEnum.HasTypeDefinition: //TODO Recognize problems with P3.7.13 HasTypeDefinition ReferenceType #39 IsProperty = _rfx.TargetNode.IsPropertyVariableType; break; - - case ReferenceKindEnum.HierarchicalReferences: - //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 - XmlQualifiedName referenceType = _rfx.GetReferenceTypeName(); - string message = - $"Id = D290E7B4-F77C-4EF0-883B-844F66471DB6; Reference {nameof(ReferenceKindEnum.HierarchicalReferences)} is not supported. Removed the graph at {referenceType.ToString()} of nodes from the model"; - _TraceEvent(TraceMessage.BuildErrorTraceMessage(BuildError.DiagnosticInformation, message)); - break; } } Dictionary _derivedChildren = m_BaseTypeNode == null ? new Dictionary() : m_BaseTypeNode.GetDerivedInstances(); @@ -239,7 +243,7 @@ void IUANodeBase.CalculateNodeReferences(INodeFactory nodeFactory, IValidator va continue; } _rc.TargetNode.RemoveInheritedValues(_instanceDeclaration); - validator.ValidateExportNode(_rc.TargetNode, nodeFactory, _rc); + validator.ValidateExportNode(_rc.TargetNode, nodeFactory, validateExportNode2Model, _rc); } catch (Exception) { throw; } } @@ -307,7 +311,7 @@ public XmlQualifiedName ExportBrowseNameBaseType(Action traceEvent) /// Dictionary<System.String, IUANodeBase>. /// Circular loop in inheritance chain //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 - public Dictionary GetDerivedInstances() + public NodesCollection GetDerivedInstances() { if (m_InGetDerivedInstances) //Improve GetDerivedInstances to log a message instead of throwing exception #651 @@ -316,15 +320,9 @@ public Dictionary GetDerivedInstances() { m_InGetDerivedInstances = true; IEnumerable _myChildren = m_AddressSpaceContext.GetChildren(this); - Dictionary _instanceDeclarations = m_BaseTypeNode == null ? new Dictionary() : m_BaseTypeNode.GetDerivedInstances(); - foreach (UANodeContext item in _myChildren) - { - string _key = item.UANode.BrowseNameQualifiedName.Name; - if (_instanceDeclarations.ContainsKey(_key)) - _instanceDeclarations[_key] = item; //replace by current item that overrides the base one - else - _instanceDeclarations.Add(_key, item); //add derived item - } + NodesCollection _instanceDeclarations = m_BaseTypeNode == null ? new NodesCollection() : m_BaseTypeNode.GetDerivedInstances(); + foreach (IUANodeBase item in _myChildren) + _instanceDeclarations.AddOrReplace(item, true); return _instanceDeclarations; } finally diff --git a/SemanticData/UANodeSetValidation/UAReferenceContext.cs b/SemanticData/UANodeSetValidation/UAReferenceContext.cs index 04e37f16..18d49b0d 100644 --- a/SemanticData/UANodeSetValidation/UAReferenceContext.cs +++ b/SemanticData/UANodeSetValidation/UAReferenceContext.cs @@ -48,7 +48,6 @@ internal UAReferenceContext(Reference reference, IAddressSpaceBuildContext addre /// Gets the kind of the reference. /// /// The kind of the reference. - //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 internal ReferenceKindEnum ReferenceKind { get @@ -116,7 +115,7 @@ internal XmlQualifiedName BrowsePath() } /// - /// Ir recursively builds the symbolic identifier. + /// It recursively builds the symbolic identifier. /// /// The browse path. internal void BuildSymbolicId(List path) @@ -189,9 +188,6 @@ private ReferenceKindEnum CalculateReferenceKind() _ret = ReferenceKindEnum.HasComponent; else if (inheritanceChain.Where(x => x.NodeIdContext == ReferenceTypeIds.HasSubtype).Any()) _ret = ReferenceKindEnum.HasSubtype; - //TODO NetworkIdentifier is missing in generated Model Design for DI model #629 - else if (inheritanceChain.Where(x => x.NodeIdContext == ReferenceTypeIds.HierarchicalReferences).Any()) - _ret = ReferenceKindEnum.HierarchicalReferences; else if (inheritanceChain.Where(x => x.NodeIdContext == ReferenceTypeIds.HasTypeDefinition).Any()) _ret = ReferenceKindEnum.HasTypeDefinition; else if (inheritanceChain.Where(x => x.NodeIdContext == ReferenceTypeIds.HasModellingRule).Any()) diff --git a/SemanticData/UANodeSetValidation/Validator.cs b/SemanticData/UANodeSetValidation/Validator.cs index d545a000..bc00c763 100644 --- a/SemanticData/UANodeSetValidation/Validator.cs +++ b/SemanticData/UANodeSetValidation/Validator.cs @@ -1,6 +1,6 @@ //__________________________________________________________________________________________________ // -// Copyright (C) 2021, Mariusz Postol LODZ POLAND. +// Copyright (C) 2022, Mariusz Postol LODZ POLAND. // // To be in touch join the community at GitHub: https://github.com/mpostol/OPC-UA-OOI/discussions //__________________________________________________________________________________________________ @@ -31,16 +31,17 @@ internal Validator(IAddressSpaceBuildContext addressSpace, IBuildErrorsHandling m_buildErrorsHandling = traceBuildErrorsHandling; } - #region internal API + #region IValidator /// /// Validates and exports it using an object of type. /// /// The node context to be validated and exported. /// A model export factory. - public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory) + /// It creates the node at the top level of the model. Called if the node has reference to another node that cannot be defined as a child. + public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory, Action validateExportNode2Model) { - ValidateExportNode(nodeContext, exportFactory, null); + ValidateExportNode(nodeContext, exportFactory, validateExportNode2Model, null); } /// @@ -49,7 +50,8 @@ public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFac /// The node context to be validated and exported. /// A model export factory. /// The reference to parent node. - public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory, UAReferenceContext parentReference) + /// It creates the node at the top level of the model. Called if the node has reference to another node that cannot be defined as a child. + public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFactory, Action validateExportNode2Model, UAReferenceContext parentReference) { Debug.Assert(nodeContext != null, "Validator.ValidateExportNode the argument nodeContext is null."); //TODO Handle HasComponent ReferenceType errors. #42 @@ -70,38 +72,38 @@ public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFac switch (nodeContext.UANode.NodeClassEnum) { case NodeClassEnum.UADataType: - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateType); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateType, validateExportNode2Model); break; case NodeClassEnum.UAMethod: - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y, parentReference), UpdateInstance); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y, parentReference), UpdateInstance, validateExportNode2Model); break; case NodeClassEnum.UAObject: - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateInstance); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateInstance, validateExportNode2Model); break; case NodeClassEnum.UAObjectType: - CreateNode(exportFactory.AddNodeFactory, nodeContext, Update, UpdateType); + CreateNode(exportFactory.AddNodeFactory, nodeContext, Update, UpdateType, validateExportNode2Model); break; case NodeClassEnum.UAReferenceType: - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateType); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateType, validateExportNode2Model); break; case NodeClassEnum.UAVariable: if (parentReference.ReferenceKind == ReferenceKindEnum.HasProperty) - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y, nodeContext, parentReference), UpdateInstance); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y, nodeContext, parentReference), UpdateInstance, validateExportNode2Model); else - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y, nodeContext, parentReference), UpdateInstance); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y, nodeContext, parentReference), UpdateInstance, validateExportNode2Model); break; case NodeClassEnum.UAVariableType: - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateType); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateType, validateExportNode2Model); break; case NodeClassEnum.UAView: - CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateInstance); + CreateNode(exportFactory.AddNodeFactory, nodeContext, (x, y) => Update(x, y), UpdateInstance, validateExportNode2Model); break; case NodeClassEnum.Unknown: @@ -110,7 +112,7 @@ public void ValidateExportNode(IUANodeBase nodeContext, INodeContainer exportFac } } - #endregion internal API + #endregion IValidator #region private @@ -245,13 +247,14 @@ private void CreateNode Func createNode, IUANodeBase nodeContext, Action updateNode, - Action updateBase + Action updateBase, + Action validateExportNode2Model ) where FactoryType : INodeFactory where NodeSetType : UANode { FactoryType _nodeFactory = createNode(); - nodeContext.CalculateNodeReferences(_nodeFactory, this); + nodeContext.CalculateNodeReferences(_nodeFactory, this, validateExportNode2Model); NodeSetType _nodeSet = (NodeSetType)nodeContext.UANode; XmlQualifiedName _browseName = nodeContext.ExportNodeBrowseName(); string _symbolicName;