Bläddra i källkod

_begin also needs to add the parent reference.

See the corresponding discussion in #1565
Stefan Profanter 6 år sedan
förälder
incheckning
f4a020abd2

+ 23 - 12
include/ua_server.h

@@ -985,12 +985,26 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  * pseudo-random unique NodeIds. Existing children are detected during the
  * _finish part via their matching BrowseName.
  *
- * The _begin method prepares the node and adds it to the nodestore. It may copy
- * some unassigned attributes from the TypeDefinition node internally. The
- * _finish method adds the references to the parent (and the TypeDefinition if
- * applicable), copies mandatory children, performs type-checking of variables
- * and calls the node constructor(s) at the end. The _finish method may remove
- * the node if it encounters an error. */
+ * The _begin method:
+ *  - prepares the node and adds it to the nodestore
+ *  - copies some unassigned attributes from the TypeDefinition node internally
+ *  - adds the references to the parent (and the TypeDefinition if applicable)
+ *  - performs type-checking of variables.
+ *
+ * You can add an object node without a parent if you set the parentNodeId and
+ * referenceTypeId to UA_NODE_ID_NULL. Then you need to add the parent reference
+ * and hasTypeDef reference yourself before calling the _finish method.
+ * Not that this is only allowed for object nodes.
+ *
+ * The _finish method:
+ *  - copies mandatory children
+ *  - calls the node constructor(s) at the end
+ *  - may remove the node if it encounters an error.
+ *
+ * The special UA_Server_addMethodNode_finish method needs to be used for
+ * method nodes, since there you need to explicitly specifiy the input
+ * and output arguments which are added in the finish step (if not yet already there)
+ **/
 
 /* The ``attr`` argument must have a type according to the NodeClass.
  * ``VariableAttributes`` for variables, ``ObjectAttributes`` for objects, and
@@ -999,21 +1013,18 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_StatusCode UA_EXPORT
 UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
                         const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId,
+                        const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName,
                         const UA_NodeId typeDefinition,
                         const void *attr, const UA_DataType *attributeType,
                         void *nodeContext, UA_NodeId *outNewNodeId);
 
 UA_StatusCode UA_EXPORT
-UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
-                         const UA_NodeId parentNodeId,
-                         const UA_NodeId referenceTypeId,
-                         const UA_NodeId typeDefinitionId);
+UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId);
 
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
-                         const UA_NodeId parentNodeId,
-                         const UA_NodeId referenceTypeId,
                          UA_MethodCallback method,
                          size_t inputArgumentsSize, const UA_Argument* inputArguments,
                          size_t outputArgumentsSize, const UA_Argument* outputArguments);

+ 4 - 3
src/server/ua_server_internal.h

@@ -341,13 +341,14 @@ UA_Discovery_removeRecord(UA_Server *server, const UA_String *servername,
 /* Creates a new node in the nodestore. */
 UA_StatusCode
 Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
-                        const UA_AddNodesItem *item, UA_NodeId *outNewNodeId);
+                        const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
+                        const UA_NodeId *referenceTypeId,
+                        UA_NodeId *outNewNodeId);
 
 /* Children, references, type-checking, constructors. */
 UA_StatusCode
 Operation_addNode_finish(UA_Server *server, UA_Session *session,
-                         const UA_NodeId *nodeId, const UA_NodeId *parentNodeId,
-                         const UA_NodeId *referenceTypeId, const UA_NodeId *typeDefinitionId);
+                         const UA_NodeId *nodeId);
 
 /**********************/
 /* Create Namespace 0 */

+ 18 - 13
src/server/ua_server_ns0.c

@@ -30,19 +30,24 @@ addNode_begin(UA_Server *server, UA_NodeClass nodeClass,
     item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     item.nodeAttributes.content.decoded.data = attributes;
     item.nodeAttributes.content.decoded.type = attributesType;
-    return Operation_addNode_begin(server, &adminSession, NULL, &item, NULL);
+    UA_NodeId parentNode = UA_NODEID_NULL;
+    UA_NodeId referenceType = UA_NODEID_NULL;
+    return Operation_addNode_begin(server, &adminSession, NULL, &item, &parentNode, &referenceType, NULL);
 }
 
 static UA_StatusCode
 addNode_finish(UA_Server *server, UA_UInt32 nodeId,
-               UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId,
-               UA_UInt32 typeDefinitionId) {
+               UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) {
+    UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId);
+    UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId);
+    UA_ExpandedNodeId targetId = UA_EXPANDEDNODEID_NUMERIC(0, parentNodeId);
+    UA_StatusCode retval = UA_Server_addReference(server, sourceId, refTypeId, targetId, UA_FALSE);
+    if (retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+
     UA_NodeId node = UA_NODEID_NUMERIC(0, nodeId);
-    UA_NodeId parentNode = UA_NODEID_NUMERIC(0, parentNodeId);
-    UA_NodeId referenceType = UA_NODEID_NUMERIC(0, referenceTypeId);
-    UA_NodeId typeDefinition = UA_NODEID_NUMERIC(0, typeDefinitionId);
-    return Operation_addNode_finish(server, &adminSession, &node, &parentNode,
-                                    &referenceType, &typeDefinition);
+    return Operation_addNode_finish(server, &adminSession, &node);
 }
 
 static UA_StatusCode
@@ -181,7 +186,7 @@ UA_Server_createNS0_base(UA_Server *server) {
                          false, false, UA_NS0ID_HASCHILD);
 
     /* Complete bootstrap of HasSubtype */
-    ret |= addNode_finish(server, UA_NS0ID_HASSUBTYPE, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE, 0);
+    ret |= addNode_finish(server, UA_NS0ID_HASSUBTYPE, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE);
 
     ret |= addReferenceTypeNode(server, "HasProperty", "PropertyOf", UA_NS0ID_HASPROPERTY,
                          false, false, UA_NS0ID_AGGREGATES);
@@ -281,24 +286,24 @@ UA_Server_createNS0_base(UA_Server *server) {
     ret |= addObjectNode(server, "ReferenceTypes", UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
     ret |= addNode_finish(server, UA_NS0ID_REFERENCES, UA_NS0ID_REFERENCETYPESFOLDER,
-                   UA_NS0ID_ORGANIZES, 0);
+                   UA_NS0ID_ORGANIZES);
 
     ret |= addObjectNode(server, "DataTypes", UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
 
     ret |= addNode_finish(server, UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER,
-                   UA_NS0ID_ORGANIZES, 0);
+                   UA_NS0ID_ORGANIZES);
 
     ret |= addObjectNode(server, "VariableTypes", UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
 
     ret |= addNode_finish(server, UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER,
-                   UA_NS0ID_ORGANIZES, 0);
+                   UA_NS0ID_ORGANIZES);
 
     ret |= addObjectNode(server, "ObjectTypes", UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
     ret |= addNode_finish(server, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER,
-                   UA_NS0ID_ORGANIZES, 0);
+                   UA_NS0ID_ORGANIZES);
 
     ret |= addObjectNode(server, "EventTypes", UA_NS0ID_EVENTTYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

+ 212 - 141
src/server/ua_services_nodemanagement.c

@@ -421,6 +421,10 @@ static void deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, UA_
 }
 
 
+static UA_StatusCode
+addParentAndTypeRef(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_NodeId *parentNodeId,
+                    const UA_NodeId *referenceTypeId, const UA_NodeId *typeDefinitionId);
+
 static UA_StatusCode
 copyChildNode(UA_Server *server, UA_Session *session,
               const UA_NodeId *destinationNodeId,
@@ -497,6 +501,15 @@ copyChildNode(UA_Server *server, UA_Session *session,
             return retval;
         }
 
+        /* Add the parent reference */
+        retval = addParentAndTypeRef(server, session, node, destinationNodeId,
+                                     &rd->referenceTypeId, typeId);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_Nodestore_delete(server, node);
+            UA_Nodestore_release(server, type);
+            return retval;
+        }
+
         /* Add all the children of this child to the new child node to make sure we take
          * the values from the nearest inherited object first.
          */
@@ -505,8 +518,7 @@ copyChildNode(UA_Server *server, UA_Session *session,
         /* Call addnode_finish, this recursively adds additional members, the type
          * definition and so on of the base type of this child, if they are not yet
          * in the destination */
-        retval = Operation_addNode_finish(server, session, &newNodeId, destinationNodeId,
-                                          &rd->referenceTypeId, typeId);
+        retval |= Operation_addNode_finish(server, session, &newNodeId);
         UA_NodeId_deleteMembers(&newNodeId);
         UA_Nodestore_release(server, type);
     }
@@ -620,6 +632,20 @@ addTypeDefRef(UA_Server *server, UA_Session *session,
     return retval;
 }
 
+static UA_StatusCode
+getTypeDef(UA_Server *server, const UA_Node *node, UA_NodeId **typeDefinitionId) {
+    UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+    for (size_t i=0; i< node->referencesSize; i++) {
+        if (node->references[i].isInverse == UA_FALSE && UA_NodeId_equal(&node->references[i].referenceTypeId, &hasTypeDef) &&
+            node->references[i].targetIdsSize > 0) {
+            *typeDefinitionId = &node->references[i].targetIds[0].nodeId;
+            return UA_STATUSCODE_GOOD;
+        }
+    }
+
+    return UA_STATUSCODE_BADNOTFOUND;
+}
+
 static UA_StatusCode
 addParentRef(UA_Server *server, UA_Session *session,
              const UA_NodeId *nodeId,
@@ -640,86 +666,6 @@ addParentRef(UA_Server *server, UA_Session *session,
 /* Add Node */
 /************/
 
-/* Prepare the node, then add it to the nodestore */
-UA_StatusCode
-Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
-                        const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) {
-    /* Do not check access for server */
-    if(session != &adminSession && server->config.accessControl.allowAddNode &&
-       !server->config.accessControl.allowAddNode(&session->sessionId, session->sessionHandle, item)) {
-        return UA_STATUSCODE_BADUSERACCESSDENIED;
-    }
-
-    /* Check the namespaceindex */
-    if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: Namespace invalid");
-        return UA_STATUSCODE_BADNODEIDINVALID;
-    }
-
-    if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED &&
-       item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: Node attributes invalid");
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
-    /* Create a node */
-    UA_Node *node = UA_Nodestore_new(server, item->nodeClass);
-    if(!node) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: Node could not create a node "
-                            "in the nodestore");
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
-
-    /* Fill the node */
-    node->context = nodeContext;
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
-    retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
-    retval |= UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data,
-                                                item->nodeAttributes.content.decoded.type);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: Node could not create a node "
-                            "with error code %s",
-                            UA_StatusCode_name(retval));
-        UA_Nodestore_delete(server, node);
-        return retval;
-    }
-
-    if(server->bootstrapNS0)
-        goto finished_checks;
-
-    /* Use attributes from the typedefinition */
-    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
-       node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
-        /* Use attributes from the type. The value and value constraints are the
-         * same for the variable and variabletype attribute structs. */
-        retval = useVariableTypeAttributes(server, session,
-                                           (UA_VariableNode*)node, item);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Using attributes from the variable type "
-                                "failed with error code %s",
-                                UA_StatusCode_name(retval));
-            UA_Nodestore_delete(server, node);
-            return retval;
-        }
-    }
-
- finished_checks:
-    /* Add the node to the nodestore */
-    retval = UA_Nodestore_insert(server, node, outNewNodeId);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: Node could not add the new node "
-                            "to the nodestore with error code %s",
-                            UA_StatusCode_name(retval));
-    }
-    return retval;
-}
 
 static void
 removeDeconstructedNode(UA_Server *server, UA_Session *session,
@@ -727,19 +673,13 @@ removeDeconstructedNode(UA_Server *server, UA_Session *session,
 
 static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
 
-/* Children, references, type-checking, constructors. */
-UA_StatusCode
-Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                         const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
-                         const UA_NodeId *typeDefinitionId) {
+static UA_StatusCode
+addParentAndTypeRef(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_NodeId *parentNodeId,
+                    const UA_NodeId *referenceTypeId, const UA_NodeId *typeDefinitionId) {
+
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     const UA_Node *type = NULL;
 
-    /* Get the node */
-    const UA_Node *node = UA_Nodestore_get(server, nodeId);
-    if(!node)
-        return UA_STATUSCODE_BADNODEIDUNKNOWN;
-
     /* Use the typeDefinition as parent for type-nodes */
     if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
        node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
@@ -764,8 +704,7 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
                             "AddNodes: The parent reference is invalid");
-        UA_Nodestore_release(server, node);
-        UA_Server_deleteNode(server, *nodeId, true);
+        UA_Server_deleteNode(server, node->nodeId, true);
         return retval;
     }
 
@@ -775,7 +714,7 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
        UA_NodeId_isNull(typeDefinitionId)) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
                             "AddNodes: No TypeDefinition; Use the default "
-                            "TypeDefinition for the Variable/Object");
+                                "TypeDefinition for the Variable/Object");
         if(node->nodeClass == UA_NODECLASS_VARIABLE)
             typeDefinitionId = &baseDataVariableType;
         else
@@ -846,7 +785,7 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
                    !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, refs, 2)) {
                     UA_LOG_INFO_SESSION(server->config.logger, session,
                                         "AddNodes: Type of variable node must "
-                                        "be VariableType and not cannot be abstract");
+                                            "be VariableType and not cannot be abstract");
                     retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                     goto cleanup;
                 }
@@ -863,7 +802,7 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
                 if(!isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, refs, 2)) {
                     UA_LOG_INFO_SESSION(server->config.logger, session,
                                         "AddNodes: Type of object node must "
-                                                "be ObjectType and not be abstract");
+                                            "be ObjectType and not be abstract");
                     retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                     goto cleanup;
                 }
@@ -882,52 +821,189 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
         if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_INFO_SESSION(server->config.logger, session,
                                 "AddNodes: Type-checking the variable node "
-                                "failed with error code %s", UA_StatusCode_name(retval));
+                                    "failed with error code %s", UA_StatusCode_name(retval));
             goto cleanup;
         }
     }
 
+
+    /* Add reference to the parent */
+    if(!UA_NodeId_isNull(parentNodeId)) {
+        if(UA_NodeId_isNull(referenceTypeId)) {
+            UA_LOG_INFO_SESSION(server->config.logger, session,
+                                "AddNodes: Reference to parent cannot be null");
+            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+            goto cleanup;
+        }
+
+        retval = addParentRef(server, session, &node->nodeId, referenceTypeId, parentNodeId);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_INFO_SESSION(server->config.logger, session,
+                                "AddNodes: Adding reference to parent failed");
+            goto cleanup;
+        }
+    }
+
+
+
     /* Instantiate variables and objects */
     if(node->nodeClass == UA_NODECLASS_VARIABLE ||
        node->nodeClass == UA_NODECLASS_OBJECT) {
         UA_assert(type != NULL); /* see above */
-        /* Add (mandatory) child nodes from the type definition */
-        if(!server->bootstrapNS0) {
-            retval = addChildren(server, session, node, type);
-            if(retval != UA_STATUSCODE_GOOD) {
-                UA_LOG_INFO_SESSION(server->config.logger, session,
-                                    "AddNodes: Adding child nodes failed with error code %s",
-                                    UA_StatusCode_name(retval));
-                goto cleanup;
-            }
-        }
-
         /* Add a hasTypeDefinition reference */
         retval = addTypeDefRef(server, session, node, type);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_INFO_SESSION(server->config.logger, session,
                                 "AddNodes: Adding a reference to the type "
-                                "definition failed with error code %s",
+                                    "definition failed with error code %s",
                                 UA_StatusCode_name(retval));
             goto cleanup;
         }
     }
 
-    /* Add reference to the parent */
-    if(!UA_NodeId_isNull(parentNodeId)) {
-        if(UA_NodeId_isNull(referenceTypeId)) {
+ cleanup:
+    if(type)
+        UA_Nodestore_release(server, type);
+    if(retval != UA_STATUSCODE_GOOD)
+        removeDeconstructedNode(server, session, node, true);
+    return retval;
+}
+
+/* Prepare the node, then add it to the nodestore */
+UA_StatusCode
+Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
+                        const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
+                        const UA_NodeId *referenceTypeId, UA_NodeId *outNewNodeId) {
+    /* Do not check access for server */
+    if(session != &adminSession && server->config.accessControl.allowAddNode &&
+       !server->config.accessControl.allowAddNode(&session->sessionId, session->sessionHandle, item)) {
+        return UA_STATUSCODE_BADUSERACCESSDENIED;
+    }
+
+    /* Check the namespaceindex */
+    if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: Namespace invalid");
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    }
+
+    if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED &&
+       item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: Node attributes invalid");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    /* Create a node */
+    UA_Node *node = UA_Nodestore_new(server, item->nodeClass);
+    if(!node) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: Node could not create a node "
+                            "in the nodestore");
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    /* Fill the node */
+    node->context = nodeContext;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
+    retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
+    retval |= UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data,
+                                                item->nodeAttributes.content.decoded.type);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: Node could not create a node "
+                            "with error code %s",
+                            UA_StatusCode_name(retval));
+        UA_Nodestore_delete(server, node);
+        return retval;
+    }
+
+    if(server->bootstrapNS0)
+        goto finished_checks;
+
+    /* Use attributes from the typedefinition */
+    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+       node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
+        /* Use attributes from the type. The value and value constraints are the
+         * same for the variable and variabletype attribute structs. */
+        retval = useVariableTypeAttributes(server, session,
+                                           (UA_VariableNode*)node, item);
+        if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Reference to parent cannot be null");
-            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+                                "AddNodes: Using attributes from the variable type "
+                                "failed with error code %s",
+                                UA_StatusCode_name(retval));
+            UA_Nodestore_delete(server, node);
+            return retval;
+        }
+    }
+
+ finished_checks:
+
+    /* Add the node to the nodestore */
+    retval = UA_Nodestore_insert(server, node, outNewNodeId);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: Node could not add the new node "
+                                "to the nodestore with error code %s",
+                            UA_StatusCode_name(retval));
+        return retval;
+    }
+
+    retval = addParentAndTypeRef(server, session, node, parentNodeId, referenceTypeId, &item->typeDefinition.nodeId);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: Node could add parent references with error code %s",
+                            UA_StatusCode_name(retval));
+        UA_Nodestore_delete(server, node);
+    }
+
+    return retval;
+}
+
+/* Children, references, type-checking, constructors. */
+UA_StatusCode
+Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+    /* Get the node */
+    const UA_Node *node = UA_Nodestore_get(server, nodeId);
+    if(!node)
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+
+    const UA_Node *type = NULL;
+
+    /* Instantiate variables and objects */
+    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+       node->nodeClass == UA_NODECLASS_OBJECT) {
+        UA_NodeId *typeDefId;
+        retval = getTypeDef(server, node, &typeDefId);
+        if (retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_INFO_SESSION(server->config.logger, session,
+                                "AddNodes: Can not get type definition of node since it has no 'hasTypeDef' reference");
             goto cleanup;
         }
 
-        retval = addParentRef(server, session, nodeId, referenceTypeId, parentNodeId);
-        if(retval != UA_STATUSCODE_GOOD) {
+        /* Get the type node */
+        type = UA_Nodestore_get(server, typeDefId);
+        if(!type) {
             UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Adding reference to parent failed");
+                                "AddNodes: Node type not found in nodestore");
+            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
             goto cleanup;
         }
+
+        /* Add (mandatory) child nodes from the type definition */
+        if(!server->bootstrapNS0) {
+            retval = addChildren(server, session, node, type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_LOG_INFO_SESSION(server->config.logger, session,
+                                    "AddNodes: Adding child nodes failed with error code %s",
+                                    UA_StatusCode_name(retval));
+                goto cleanup;
+            }
+        }
     }
 
     /* Call the constructor(s) */
@@ -951,15 +1027,13 @@ static void
 Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext,
                   const UA_AddNodesItem *item, UA_AddNodesResult *result) {
     result->statusCode = Operation_addNode_begin(server, session, nodeContext,
-                                                 item, &result->addedNodeId);
+                                                 item, &item->parentNodeId.nodeId, &item->referenceTypeId, &result->addedNodeId);
     if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
 
     /* AddNodes_finish */
     result->statusCode =
-        Operation_addNode_finish(server, session, &result->addedNodeId,
-                                 &item->parentNodeId.nodeId, &item->referenceTypeId,
-                                 &item->typeDefinition.nodeId);
+        Operation_addNode_finish(server, session, &result->addedNodeId);
 
     /* If finishing failed, the node was deleted */
     if(result->statusCode != UA_STATUSCODE_GOOD)
@@ -1021,6 +1095,8 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
 UA_StatusCode
 UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
                         const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId,
+                        const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName,
                         const UA_NodeId typeDefinition,
                         const void *attr, const UA_DataType *attributeType,
@@ -1035,16 +1111,13 @@ UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
     item.nodeAttributes.content.decoded.type = attributeType;
     item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
     return Operation_addNode_begin(server, &adminSession, nodeContext,
-                                   &item, outNewNodeId);
+                                   &item, &parentNodeId, &referenceTypeId,
+                                   outNewNodeId);
 }
 
 UA_StatusCode
-UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
-                         const UA_NodeId parentNodeId,
-                         const UA_NodeId referenceTypeId,
-                         const UA_NodeId typeDefinitionId) {
-    return Operation_addNode_finish(server, &adminSession, &nodeId, &parentNodeId,
-                                    &referenceTypeId, &typeDefinitionId);
+UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) {
+    return Operation_addNode_finish(server, &adminSession, &nodeId);
 }
 
 /****************/
@@ -1440,6 +1513,10 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     item.nodeClass = UA_NODECLASS_VARIABLE;
     item.requestedNewNodeId.nodeId = requestedNewNodeId;
     item.browseName = browseName;
+    UA_ExpandedNodeId typeDefinitionId;
+    UA_ExpandedNodeId_init(&typeDefinitionId);
+    typeDefinitionId.nodeId = typeDefinition;
+    item.typeDefinition = typeDefinitionId;
     item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
     item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
@@ -1451,13 +1528,12 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         deleteNodeId = UA_TRUE;
     }
     UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, nodeContext,
-                                                   &item, outNewNodeId);
+                                                   &item, &parentNodeId, &referenceTypeId, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     retval = UA_Server_setVariableNode_dataSource(server, *outNewNodeId, dataSource);
     if(retval == UA_STATUSCODE_GOOD)
-        retval = Operation_addNode_finish(server, &adminSession, outNewNodeId,
-                                          &parentNodeId, &referenceTypeId, &typeDefinition);
+        retval = Operation_addNode_finish(server, &adminSession, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD || deleteNodeId)
         UA_NodeId_deleteMembers(outNewNodeId);
     return retval;
@@ -1494,7 +1570,6 @@ static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPE
 
 static UA_StatusCode
 UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
-                                 const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                  UA_MethodCallback method,
                                  const size_t inputArgumentsSize, const UA_Argument *inputArguments,
                                  const UA_NodeId inputArgumentsRequestedNewNodeId,
@@ -1570,8 +1645,7 @@ UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
     retval |= UA_Server_setMethodNode_callback(server, nodeId, method);
 
     /* Call finish to add the parent reference */
-    retval |= Operation_addNode_finish(server, &adminSession, &nodeId, &parentNodeId,
-                                       &referenceTypeId, &UA_NODEID_NULL);
+    retval |= Operation_addNode_finish(server, &adminSession, &nodeId);
 
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Server_deleteNode(server, nodeId, true);
@@ -1591,12 +1665,10 @@ UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
 
 UA_StatusCode
 UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
-                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                UA_MethodCallback method,
                                size_t inputArgumentsSize, const UA_Argument* inputArguments,
                                size_t outputArgumentsSize, const UA_Argument* outputArguments) {
-    return UA_Server_addMethodNodeEx_finish(server, nodeId, parentNodeId,
-                                            referenceTypeId, method,
+    return UA_Server_addMethodNodeEx_finish(server, nodeId, method,
                                             inputArgumentsSize, inputArguments, UA_NODEID_NULL, NULL,
                                             outputArgumentsSize, outputArguments, UA_NODEID_NULL, NULL);
 }
@@ -1630,12 +1702,11 @@ UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId,
     }
 
     UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, nodeContext,
-                                                   &item, outNewNodeId);
+                                                   &item, &parentNodeId, &referenceTypeId, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    retval = UA_Server_addMethodNodeEx_finish(server, *outNewNodeId,
-                                              parentNodeId, referenceTypeId, method,
+    retval = UA_Server_addMethodNodeEx_finish(server, *outNewNodeId, method,
                                               inputArgumentsSize, inputArguments,
                                               inputArgumentsRequestedNewNodeId,
                                               inputArgumentsOutNewNodeId,

+ 2 - 2
tools/nodeset_compiler/backend_open62541.py

@@ -227,7 +227,7 @@ extern UA_StatusCode %s(UA_Server *server);
         if not node.hidden:
             writec("\n/* " + str(node.displayName) + " - " + str(node.id) + " */")
             writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_begin(UA_Server *server, UA_UInt16* ns) {\n")
-            code = generateNodeCode_begin(node, nodeset, max_string_length)
+            code = generateNodeCode_begin(node, nodeset, max_string_length, generate_ns0, parentrefs)
             if code is None:
                 writec("/* Ignored. No parent */")
                 nodeset.hide_node(node.id)
@@ -242,7 +242,7 @@ extern UA_StatusCode %s(UA_Server *server);
         writec("return retVal;\n}")
 
         writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_finish(UA_Server *server, UA_UInt16* ns) {\n")
-        code = generateNodeCode_finish(node, generate_ns0, parentrefs)
+        code = generateNodeCode_finish(node)
         writec("return " + code + "\n}\n")
 
         functionNumber = functionNumber + 1

+ 15 - 23
tools/nodeset_compiler/backend_open62541_nodes.py

@@ -459,7 +459,7 @@ def generateSubtypeOfDefinitionCode(node):
             return generateNodeIdCode(ref.target)
     return "UA_NODEID_NULL"
 
-def generateNodeCode_begin(node, nodeset, max_string_length):
+def generateNodeCode_begin(node, nodeset, max_string_length, generate_ns0, parentrefs):
     code = []
     code.append("UA_StatusCode retVal = UA_STATUSCODE_GOOD;")
 
@@ -492,9 +492,19 @@ def generateNodeCode_begin(node, nodeset, max_string_length):
     code.append("attr.userWriteMask = %d;" % node.userWriteMask)
 
     typeDef = getNodeTypeDefinition(node)
+    isDataTypeEncodingType = typeDef is not None and typeDef.ns == 0 and typeDef.i == 76
+    # Object nodes of type DataTypeEncoding do not have any parent
+    if not generate_ns0 and not isDataTypeEncodingType:
+        (parentNode, parentRef) = extractNodeParent(node, parentrefs)
+        if parentNode is None or parentRef is None:
+            return None
+    else:
+        (parentNode, parentRef) = (NodeId(), NodeId())
 
     code.append("retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_{},".format(node.__class__.__name__.upper().replace("NODE" ,"")))
     code.append(generateNodeIdCode(node.id) + ",")
+    code.append(generateNodeIdCode(parentNode) + ",")
+    code.append(generateNodeIdCode(parentRef) + ",")
     code.append(generateQualifiedNameCode(node.browseName, max_string_length=max_string_length) + ",")
     if isinstance(node, VariableTypeNode):
         # we need the HasSubtype reference
@@ -514,38 +524,20 @@ def generateNodeCode_begin(node, nodeset, max_string_length):
     
     return "\n".join(code)
 
-def generateNodeCode_finish(node, generate_ns0, parentrefs):
+def generateNodeCode_finish(node):
     code = []
 
-    typeDef = getNodeTypeDefinition(node)
-    isDataTypeEncodingType = typeDef is not None and typeDef.ns == 0 and typeDef.i == 76
-    # Object nodes of type DataTypeEncoding do not have any parent
-    if not generate_ns0 and not isDataTypeEncodingType:
-        (parentNode, parentRef) = extractNodeParent(node, parentrefs)
-        if parentNode is None or parentRef is None:
-            return None
-    else:
-        (parentNode, parentRef) = (NodeId(), NodeId())
-
 
     if isinstance(node, MethodNode):
         code.append("UA_Server_addMethodNode_finish(server, ")
     else:
         code.append("UA_Server_addNode_finish(server, ")
-    code.append(generateNodeIdCode(node.id) + ",")
-    code.append(generateNodeIdCode(parentNode) + ",")
-    code.append(generateNodeIdCode(parentRef) + ",")
+    code.append(generateNodeIdCode(node.id))
 
     if isinstance(node, MethodNode):
-        code.append("NULL, 0, NULL, 0, NULL);")
+        code.append(", NULL, 0, NULL, 0, NULL);")
     else:
-
-        if isinstance(node, VariableTypeNode):
-            # we need the HasSubtype reference
-            code.append(generateSubtypeOfDefinitionCode(node) + ");")
-        else:
-            typeDefCode = "UA_NODEID_NULL" if typeDef is None else generateNodeIdCode(typeDef)
-            code.append(typeDefCode + ");")
+        code.append(");")
 
     return "\n".join(code)