/// <summary>
        /// Creates an Object node in the address space.
        /// </summary>
        public NodeId CreateObject(
            NodeId           parentId,
            NodeId           referenceTypeId,
            NodeId           nodeId,
            QualifiedName    browseName,
            ObjectAttributes attributes,
            ExpandedNodeId   typeDefinitionId)
        {
            try
            {
                m_lock.Enter();

                // validate browse name.
                if (QualifiedName.IsNull(browseName))
                {
                    throw ServiceResultException.Create(StatusCodes.BadBrowseNameInvalid, "BrowsName must not be empty.");
                }

                // check for null node id.
                if (NodeId.IsNull(nodeId))
                {
                    nodeId = CreateUniqueNodeId();
                }

                // check if node id exists.
                if (m_nodes.Exists(nodeId))
                {
                    throw ServiceResultException.Create(StatusCodes.BadNodeIdExists, "NodeId '{0}' already exists.", nodeId);
                }

                // find parent.
                ILocalNode parent = null;

                if (!NodeId.IsNull(parentId))
                {
                    parent = GetManagerHandle(parentId) as ILocalNode;

                    if (parent == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadParentNodeIdInvalid, "Parent node '{0}' does not exist.", parentId);
                    }

                    // validate reference.
                    ValidateReference(parent, referenceTypeId, false, NodeClass.Object);
                }

                // find type definition.
                if (NodeId.IsNull(typeDefinitionId))
                {
                    typeDefinitionId = ObjectTypes.BaseObjectType;
                }

                IObjectType objectType = GetManagerHandle(typeDefinitionId) as IObjectType;

                if (objectType == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadTypeDefinitionInvalid, "Type definition '{0}' does not exist or is not an ObjectType.", typeDefinitionId);
                }                               

                // verify instance declarations.
                ILocalNode instanceDeclaration = FindInstanceDeclaration(parent, browseName);

                if (instanceDeclaration != null)
                {
                    if (instanceDeclaration.NodeClass != NodeClass.Object)
                    {                        
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The type model requires that node with a browse name of {0} have a NodeClass of {1}.", 
                            browseName,
                            instanceDeclaration.NodeClass);
                    }

                    if (!m_server.TypeTree.IsTypeOf(typeDefinitionId, instanceDeclaration.TypeDefinitionId))
                    {
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The type model requires that node have a type definition of {0}.", 
                            instanceDeclaration.TypeDefinitionId);
                    }
                }

                // get the variable.
                IObject objectd = instanceDeclaration as IObject;

                // create node.
                ObjectNode node = new ObjectNode();

                // set defaults from type definition.
                node.NodeId        = nodeId;
                node.NodeClass     = NodeClass.Object;
                node.BrowseName    = browseName;
                node.DisplayName   = browseName.Name;
                node.Description   = null;
                node.WriteMask     = 0;
                node.UserWriteMask = 0;
                node.EventNotifier = EventNotifiers.None;

                // set defaults from instance declaration.
                if (objectd != null)
                {
                    node.DisplayName   = objectd.DisplayName;
                    node.Description   = objectd.Description;
                    node.WriteMask     = (uint)objectd.WriteMask;
                    node.UserWriteMask = (uint)objectd.UserWriteMask;
                    node.EventNotifier = objectd.EventNotifier;
                }            
                      
                // update with attributes provided.
                UpdateAttributes(node, attributes);

                // EventNotifier    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.EventNotifier) != 0)
                {
                    node.EventNotifier = attributes.EventNotifier;
                }

                // add references with parent.
                if (parent != null)
                {
                    AddReference(parent, referenceTypeId, false, node, true);                
                }
                
                // add type definition.
                AddReference(node, ReferenceTypeIds.HasTypeDefinition, false, objectType, false);     

                // add to address space.
                AddNode(node);
                                
                // apply modelling rules.
                NodeFactory factory = new NodeFactory(m_nodes);

                IList<ILocalNode> nodesToAdd = factory.ApplyModellingRules(node, objectType.NodeId, ref m_lastId, 1);
                
                // add the nodes.
                foreach (Node nodeToAdd in nodesToAdd)
                {               
                    AddNode(nodeToAdd);
                }
                
                // find the top level parent that must be used to apply the modelling rules.
                if (instanceDeclaration != null)
                {
                    ILocalNode toplevelParent = FindTopLevelModelParent(parent);
                    
                    // add modelling rule.
                    AddReference(node, ReferenceTypeIds.HasModelParent, false, parent, true);     
                                    
                    // update the hierarchy.
                    nodesToAdd = factory.ApplyModellingRules(toplevelParent, (NodeId)toplevelParent.TypeDefinitionId, ref m_lastId, 1);
                    
                    // add the nodes.
                    foreach (Node nodeToAdd in nodesToAdd)
                    {               
                        AddNode(nodeToAdd);
                    }
                }

                // return the new node id.
                return node.NodeId;
            }
            finally
            {
                m_lock.Exit();
            } 
        }        
        public NodeId CreateVariable(
            NodeId             parentId,
            NodeId             referenceTypeId,
            NodeId             nodeId,
            QualifiedName      browseName,
            VariableAttributes attributes,
            ExpandedNodeId     typeDefinitionId)
        {
            try
            {
                m_lock.Enter();

                // check browse name.
                if (QualifiedName.IsNull(browseName))
                {
                    throw new ServiceResultException(StatusCodes.BadBrowseNameInvalid);
                }

                // user default type definition.
                if (NodeId.IsNull(typeDefinitionId))
                {
                    typeDefinitionId = VariableTypes.BaseDataVariableType;
                }
                
                // find type definition.
                IVariableType variableType = GetManagerHandle(typeDefinitionId) as IVariableType;

                if (variableType == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadTypeDefinitionInvalid, "Type definition '{0}' does not exist or is not an VariableType.", typeDefinitionId);
                }

                // check if node id exists.
                if (!NodeId.IsNull(nodeId))
                {
                    if (m_nodes.Exists(nodeId))
                    {
                        throw ServiceResultException.Create(StatusCodes.BadNodeIdExists, "NodeId '{0}' already exists.", nodeId);
                    }
                }

                // create a unique id.
                else
                {
                    nodeId = CreateUniqueNodeId();
                }

                // find parent.
                ILocalNode parent =  null;
                
                if (!NodeId.IsNull(parentId))
                {
                    parent = GetManagerHandle(parentId) as ILocalNode;

                    if (parent == null)
                    {
                        throw ServiceResultException.Create(StatusCodes.BadParentNodeIdInvalid, "Parent node '{0}' does not exist.", parentId);
                    }

                    // validate reference.
                    ValidateReference(parent, referenceTypeId, false, NodeClass.Variable);
                }
   
                // verify instance declarations.
                ILocalNode instanceDeclaration = FindInstanceDeclaration(parent, browseName);

                if (instanceDeclaration != null)
                {
                    if (instanceDeclaration.NodeClass != NodeClass.Variable)
                    {                        
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The type model requires that node with a browse name of {0} have a NodeClass of {1}.", 
                            browseName,
                            instanceDeclaration.NodeClass);
                    }

                    if (!m_server.TypeTree.IsTypeOf(typeDefinitionId, instanceDeclaration.TypeDefinitionId))
                    {
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The type model requires that node have a type definition of {0}.", 
                            instanceDeclaration.TypeDefinitionId);
                    }
                }

                // get the variable.
                IVariable variable = instanceDeclaration as IVariable;

                // create node.
                VariableNode node = new VariableNode();

                // set defaults from type definition.
                node.NodeId                  = nodeId;
                node.NodeClass               = NodeClass.Variable;
                node.BrowseName              = browseName;
                node.DisplayName             = browseName.Name;
                node.Description             = null;
                node.WriteMask               = 0;
                node.UserWriteMask           = 0;
                node.Value                   = (variable == null)?new Variant(Utils.Clone(variableType.Value)):Variant.Null;
                node.DataType                = variableType.DataType;
                node.ValueRank               = variableType.ValueRank;
                node.ArrayDimensions         = new UInt32Collection(variableType.ArrayDimensions);
                node.AccessLevel             = AccessLevels.CurrentReadOrWrite;
                node.UserAccessLevel         = node.AccessLevel;
                node.MinimumSamplingInterval = MinimumSamplingIntervals.Indeterminate;
                node.Historizing             = false;
                
                // set defaults from instance declaration.
                if (variable != null)
                {
                    node.DisplayName             = variable.DisplayName;
                    node.Description             = variable.Description;
                    node.WriteMask               = (uint)variable.WriteMask;
                    node.UserWriteMask           = (uint)variable.UserWriteMask;
                    node.Value                   = new Variant(Utils.Clone(variable.Value));
                    node.DataType                = variable.DataType;
                    node.ValueRank               = variable.ValueRank;
                    node.ArrayDimensions         = new UInt32Collection(variable.ArrayDimensions);
                    node.AccessLevel             = variable.AccessLevel;
                    node.UserAccessLevel         = variable.UserAccessLevel;
                    node.MinimumSamplingInterval = variable.MinimumSamplingInterval;
                    node.Historizing             = variable.Historizing;
                }            
                      
                // update attributes.
                UpdateAttributes(node, attributes);

                // Value    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.Value) != 0)
                {
                    node.Value = attributes.Value;
                }
   
                // DataType    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.DataType) != 0)
                {
                    if (!m_server.TypeTree.IsTypeOf(attributes.DataType, variableType.DataType))
                    {
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The type definition requires a DataType of {0}.", 
                            variableType.DataType);
                    }

                    if (variable != null)
                    {
                        if (!m_server.TypeTree.IsTypeOf(attributes.DataType, variable.DataType))
                        {
                            throw ServiceResultException.Create(
                                StatusCodes.BadNodeClassInvalid, 
                                "The instance declaration requires a DataType of {0}.", 
                                variable.DataType);
                        }
                    }

                    node.DataType = attributes.DataType;
                }
     
                // ValueRank    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.ValueRank) != 0)
                {
                    if (!ValueRanks.IsValid(attributes.ValueRank, variableType.ValueRank))
                    {
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The type definition requires a ValueRank of {0}.", 
                            variableType.ValueRank);
                    }

                    if (variable != null)
                    {
                        if (!ValueRanks.IsValid(attributes.ValueRank, variable.ValueRank))
                        {
                            throw ServiceResultException.Create(
                                StatusCodes.BadNodeClassInvalid, 
                                "The instance declaration requires a ValueRank of {0}.", 
                                variable.ValueRank);
                        }
                    }

                    node.ValueRank = attributes.ValueRank;
                }
                        
                // ArrayDimensions    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.ArrayDimensions) != 0)
                {
                    if (!ValueRanks.IsValid(attributes.ArrayDimensions, node.ValueRank, variableType.ArrayDimensions))
                    {
                        throw ServiceResultException.Create(
                            StatusCodes.BadNodeClassInvalid, 
                            "The ArrayDimensions do not meet the requirements for the type definition: {0}.", 
                            variableType.NodeId);
                    }

                    if (variable != null)
                    {
                        if (!ValueRanks.IsValid(attributes.ArrayDimensions, node.ValueRank, variable.ArrayDimensions))
                        {
                            throw ServiceResultException.Create(
                                StatusCodes.BadNodeClassInvalid, 
                                "The ArrayDimensions do not meet the requirements for the instance declaration: {0}.", 
                                variable.ValueRank);
                        }
                    }

                    node.ArrayDimensions = attributes.ArrayDimensions;
                }
                        
                // AccessLevel    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.AccessLevel) != 0)
                {
                    node.AccessLevel = attributes.AccessLevel;
                }                
                        
                // AccessLevel    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.UserAccessLevel) != 0)
                {
                    node.UserAccessLevel = attributes.UserAccessLevel;
                }                         
                        
                // MinimumSamplingInterval    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.MinimumSamplingInterval) != 0)
                {
                    node.MinimumSamplingInterval = attributes.MinimumSamplingInterval;
                }
      
                // Historizing    
                if (attributes != null && (attributes.SpecifiedAttributes & (uint)NodeAttributesMask.Historizing) != 0)
                {
                    node.Historizing = attributes.Historizing;
                }  
                
                // add references with parent.
                if (parent != null)
                {
                    AddReference(parent, referenceTypeId, false, node, true);                
                }

                // add type definition.
                AddReference(node, ReferenceTypeIds.HasTypeDefinition, false, variableType, false);     
                                
                // add to address space.
                AddNode(node);
                
                // apply modelling rules.
                NodeFactory factory = new NodeFactory(m_nodes);

                IList<ILocalNode> nodesToAdd = factory.ApplyModellingRules(node, variableType.NodeId, ref m_lastId, 1);
                
                // add the nodes.
                foreach (Node nodeToAdd in nodesToAdd)
                {               
                    AddNode(nodeToAdd);
                }

                // add references with parent.
                if (parent != null)
                {
                    AddReference(parent, referenceTypeId, false, node, true);                
                }
                
                // find the top level parent that must be used to apply the modelling rules.
                if (instanceDeclaration != null)
                {
                    ILocalNode toplevelParent = FindTopLevelModelParent(parent);
                    
                    // add modelling rule.
                    AddReference(node, ReferenceTypeIds.HasModelParent, false, parent, true);     
                                    
                    // update the hierarchy.
                    nodesToAdd = factory.ApplyModellingRules(toplevelParent, (NodeId)toplevelParent.TypeDefinitionId, ref m_lastId, 1);
                    
                    // add the nodes.
                    foreach (Node nodeToAdd in nodesToAdd)
                    {               
                        AddNode(nodeToAdd);
                    }
                }

                // return the new node id.
                return node.NodeId;
            }
            finally
            {
                m_lock.Exit();
            } 
        }
        /// <summary>
        /// Changes the type definition for an instance.
        /// </summary>
        public void ChangeTypeDefinition(
            NodeId instanceId,
            NodeId typeDefinitionId)
        {
            try
            {
                m_lock.Enter();

                // find the instance.                
                ILocalNode instance = GetLocalNode(instanceId) as ILocalNode;

                if (instance == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadNodeIdUnknown, "NodeId ({0}) does not exist.", instanceId);
                }

                // check node class.
                if (instance.NodeClass != NodeClass.Object && instance.NodeClass != NodeClass.Variable)
                {
                    throw ServiceResultException.Create(StatusCodes.BadNodeClassInvalid, "Node (NodeClass={0}) cannot have a type definition.", instance.NodeClass);
                }

                // get current type definition.
                ExpandedNodeId existingTypeId = instance.TypeDefinitionId;

                if (existingTypeId == typeDefinitionId)
                {
                    return;
                }

                // can only change to a subtype of the existing type definition.
                if (!m_server.TypeTree.IsTypeOf(typeDefinitionId, existingTypeId))
                {
                    throw ServiceResultException.Create(StatusCodes.BadTypeDefinitionInvalid, "Type definition ({0}) must be a must subtype of the existing type definition ({1}).", typeDefinitionId, existingTypeId);
                }

                // find the type definition node.
                ILocalNode typeDefinition = GetLocalNode(typeDefinitionId) as ILocalNode;

                if (typeDefinition == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadTypeDefinitionInvalid, "TypeDefinitionId ({0}) does not exist.", typeDefinitionId);
                }

                // apply modelling rules.
                NodeFactory factory = new NodeFactory(m_nodes);
                IList<ILocalNode> nodesToAdd = factory.ApplyModellingRules(instance, typeDefinition.NodeId, ref m_lastId, 1);

                // add the nodes.
                foreach (Node nodeToAdd in nodesToAdd)
                {
                    AddNode(nodeToAdd);
                }
            }
            finally
            {
                m_lock.Exit();
            }
        }