Opc.Ua.Server.CoreNodeManager.ApplyModellingRules C# (CSharp) Method

ApplyModellingRules() private method

private ApplyModellingRules ( ILocalNode instance, ILocalNode typeDefinition, ILocalNode templateDeclaration, ushort namespaceIndex ) : void
instance ILocalNode
typeDefinition ILocalNode
templateDeclaration ILocalNode
namespaceIndex ushort
return void
        public void ApplyModellingRules(
            ILocalNode instance, 
            ILocalNode typeDefinition, 
            ILocalNode templateDeclaration, 
            ushort     namespaceIndex)
        {
            if (instance == null) throw new ArgumentNullException("instance");
            if (typeDefinition == null) throw new ArgumentNullException("typeDefinition");

            // check existing type definition.
            UpdateTypeDefinition(instance, typeDefinition.NodeId);

            // create list of declarations for the type definition (recursively collects definitions from supertypes).
            List<DeclarationNode> declarations = new List<DeclarationNode>();
            BuildDeclarationList(typeDefinition, declarations);
            
            // add instance declaration if provided.
            if (templateDeclaration != null)
            {
                DeclarationNode declaration = new DeclarationNode();

                declaration.Node = templateDeclaration;
                declaration.BrowsePath = String.Empty;

                declarations.Add(declaration);

                BuildDeclarationList(templateDeclaration, declarations);
            }

            // build list of instances to create.
            List<ILocalNode> typeDefinitions = new List<ILocalNode>();
            SortedDictionary<string,ILocalNode> instanceDeclarations = new SortedDictionary<string,ILocalNode>();
            SortedDictionary<NodeId,ILocalNode> possibleTargets = new SortedDictionary<NodeId,ILocalNode>();
            
            // create instances from declarations.
            // subtypes appear in list last so traversing the list backwards find the overridden nodes first.
            for (int ii = declarations.Count-1; ii >= 0; ii--)
            {
                DeclarationNode declaration = declarations[ii];
                
                // update type definition list.
                if (String.IsNullOrEmpty(declaration.BrowsePath))
                {
                    typeDefinitions.Add(declaration.Node);
                    continue;
                }

                // skip declaration if instance already exists.
                // (i.e. the declaration was overridden).
                if (instanceDeclarations.ContainsKey(declaration.BrowsePath))
                {
                    continue;
                }
                
                // update instance declaration list.
                instanceDeclarations[declaration.BrowsePath] = declaration.Node;
                                        
                // save the node as a possible target of references.
                possibleTargets[declaration.Node.NodeId] = declaration.Node; 
            }
            
            // build list of instances that already exist.
            SortedDictionary<string,ILocalNode> existingInstances = new SortedDictionary<string,ILocalNode>();
            BuildInstanceList(instance, String.Empty, existingInstances);

            // maps the instance declaration onto an instance node.
            Dictionary<NodeId,ILocalNode> instancesToCreate = new Dictionary<NodeId,ILocalNode>(); 
            
            // apply modelling rules to instance declarations.
            foreach (KeyValuePair<string,ILocalNode> current in instanceDeclarations)
            {
                string browsePath = current.Key;
                ILocalNode instanceDeclaration = current.Value;

                // check if the same instance has multiple browse paths to it.
                ILocalNode newInstance = null;
                
                if (instancesToCreate.TryGetValue(instanceDeclaration.NodeId, out newInstance))
                {   
                    continue;
                }
 
                // check for an existing instance.
                if (existingInstances.TryGetValue(browsePath, out newInstance))
                {
                    continue;
                }

                // apply modelling rule to determine whether to create a new instance.
                NodeId modellingRule = instanceDeclaration.ModellingRule;
                
                // always create a new instance if one does not already exist.
                if (modellingRule == Objects.ModellingRule_Mandatory)
                {               
                    if (newInstance == null)
                    {
                        newInstance = instanceDeclaration.CreateCopy(CreateUniqueNodeId());
                        AddNode(newInstance);
                    }
                }

                // ignore optional instances unless one has been specified in the existing tree.
                else if (modellingRule == Objects.ModellingRule_Optional)
                {                            
                    if (newInstance == null)
                    {
                        continue;
                    }
                }

                // always use the declaration node.
                else if (modellingRule == Objects.ModellingRule_MandatoryShared)
                {                            
                    newInstance = instanceDeclaration;
                }

                // ignore any unknown modelling rules.
                else
                {
                    continue;
                }

                // save the mapping between the instance declaration and the new instance.
                instancesToCreate[instanceDeclaration.NodeId] = newInstance;
            }
            
            // add references from type definitions to top level.
            foreach (ILocalNode type in typeDefinitions)
            {
                foreach (IReference reference in type.References)
                {
                    // ignore external references from type.
                    if (reference.TargetId.IsAbsolute)
                    {
                        continue;
                    }
                    
                    // ignore subtype references.
                    if (m_nodes.TypeTree.IsTypeOf(reference.ReferenceTypeId, ReferenceTypeIds.HasSubtype))
                    {
                        continue;                            
                    }

                    // ignore targets that are not in the instance tree.
                    ILocalNode target = null;

                    if (!instancesToCreate.TryGetValue((NodeId)reference.TargetId, out target))
                    {
                        continue;
                    }

                    // add forward and backward reference.
                    AddReference(instance, reference.ReferenceTypeId, reference.IsInverse, target, true);
                }                  
            }
           
            // add references between instance declarations.
            foreach (ILocalNode instanceDeclaration in instanceDeclarations.Values)
            {
                // find the source for the references.
                ILocalNode source = null;

                if (!instancesToCreate.TryGetValue(instanceDeclaration.NodeId, out source))
                {
                    continue;
                }
                
                // check if the source is a shared node.
                bool sharedNode = Object.ReferenceEquals(instanceDeclaration, source);

                foreach (IReference reference in instanceDeclaration.References)
                {
                    // add external reference.
                    if (reference.TargetId.IsAbsolute)
                    {
                        if (!sharedNode)
                        {
                            AddReference(source, reference.ReferenceTypeId, reference.IsInverse, reference.TargetId);
                        }

                        continue;
                    }

                    // check for modelling rule.
                    if (reference.ReferenceTypeId == ReferenceTypeIds.HasModellingRule)
                    {
                        if (!source.References.Exists(ReferenceTypeIds.HasModellingRule, false, reference.TargetId, false, null))
                        {
                            AddReference(source, reference.ReferenceTypeId, false, reference.TargetId);
                        }

                        continue;                            
                    }

                    // check for type definition.
                    if (reference.ReferenceTypeId == ReferenceTypeIds.HasTypeDefinition)
                    {
                        if (!sharedNode)
                        {                        
                            UpdateTypeDefinition(source, instanceDeclaration.TypeDefinitionId);
                        }

                        continue;                            
                    }

                    // add targets that are not in the instance tree.
                    ILocalNode target = null;

                    if (!instancesToCreate.TryGetValue((NodeId)reference.TargetId, out target))
                    {
                        // don't update shared nodes because the reference should already exist.
                        if (sharedNode)
                        {
                            continue;
                        }

                        // top level references to the type definition node were already added.
                        if (reference.TargetId == typeDefinition.NodeId)
                        {
                            continue;
                        }

                        // see if a reference is allowed.
                        if (!IsExternalReferenceAllowed(reference.ReferenceTypeId))
                        {
                            continue;
                        }

                        // add one way reference.
                        source.References.Add(reference.ReferenceTypeId, reference.IsInverse, reference.TargetId);
                        continue;
                    }
                                                                    
                    // add forward and backward reference.
                    AddReference(source, reference.ReferenceTypeId, reference.IsInverse, target, true);
                }
            }
        }