Переглянути джерело

refactor getTypeHierarchy and getNodeType

Julius Pfrommer 6 роки тому
батько
коміт
7ff5a873ff

+ 10 - 3
src/server/ua_server_internal.h

@@ -213,10 +213,17 @@ isNodeInTree(UA_NodeStore *ns, const UA_NodeId *leafNode,
              const UA_NodeId *nodeToFind, const UA_NodeId *referenceTypeIds,
              size_t referenceTypeIdsSize);
 
+/* Returns an array with the hierarchy of type nodes. The returned array starts
+ * at the leaf and continues "upwards" in the hierarchy based on the
+ * ``hasSubType`` references. Since multiple-inheritance is possible in general,
+ * duplicate entries are avoided. */
+UA_StatusCode
+getTypeHierarchy(UA_NodeStore *ns, const UA_NodeId *leafType,
+                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize);
 
-/* Returns the nodeid of the node type, if none defined for the node or the node
- * class, typeId is set to UA_NODEID_NULL. */
-void getNodeType(UA_Server *server, const UA_Node *node, UA_NodeId *typeId);
+/* Returns a pointer to the nodeid of the node type in the node's references. If
+ * no type is defined, a pointer to UA_NODEID_NULL is returned */
+const UA_NodeId * getNodeType(UA_Server *server, const UA_Node *node);
 
 typedef void (*UA_ServiceOperation)(UA_Server *server, UA_Session *session,
                                     const void *requestOperation, void *responseOperation);

+ 124 - 24
src/server/ua_server_utils.c

@@ -122,24 +122,27 @@ isNodeInTree(UA_NodeStore *ns, const UA_NodeId *leafNode, const UA_NodeId *nodeT
     return false;
 }
 
-void getNodeType(UA_Server *server, const UA_Node *node, UA_NodeId *typeId) {
-    UA_NodeId_init(typeId);
+const UA_NodeId *
+getNodeType(UA_Server *server, const UA_Node *node) {
     UA_NodeId parentRef;
     UA_Boolean inverse;
 
     /* The reference to the parent is different for variable and variabletype */
-    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
-       node->nodeClass == UA_NODECLASS_OBJECT) {
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+    case UA_NODECLASS_VARIABLE:
         parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         inverse = false;
-    } else if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
-              node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
-              node->nodeClass == UA_NODECLASS_REFERENCETYPE ||
-              node->nodeClass == UA_NODECLASS_DATATYPE) {
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+    case UA_NODECLASS_VARIABLETYPE:
+    case UA_NODECLASS_REFERENCETYPE:
+    case UA_NODECLASS_DATATYPE:
         parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
         inverse = true;
-    } else {
-        return;
+        break;
+    default:
+        return &UA_NODEID_NULL;
     }
 
     /* Stop at the first matching candidate */
@@ -148,37 +151,32 @@ void getNodeType(UA_Server *server, const UA_Node *node, UA_NodeId *typeId) {
             continue;
         if(!UA_NodeId_equal(&node->references[i].referenceTypeId, &parentRef))
             continue;
-        if(node->references[i].targetIdsSize == 0)
-            return;
-        UA_NodeId_copy(&node->references[i].targetIds[0].nodeId, typeId);
-        return;
+        UA_assert(node->references[i].targetIdsSize > 0);
+        return &node->references[i].targetIds[0].nodeId;
     }
+    return &UA_NODEID_NULL;
 }
 
 const UA_VariableTypeNode *
 getVariableNodeType(UA_Server *server, const UA_VariableNode *node) {
-    UA_NodeId vtId;
-    getNodeType(server, (const UA_Node*)node, &vtId);
-
-    const UA_Node *vt = UA_NodeStore_get(server->nodestore, &vtId);
+    const UA_NodeId *vtId = getNodeType(server, (const UA_Node*)node);
+    const UA_Node *vt = UA_NodeStore_get(server->nodestore, vtId);
     if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE) {
-        vt = NULL;
         UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER,
                      "No VariableType for the node found");
+        return NULL;
     }
     return (const UA_VariableTypeNode*)vt;
 }
 
 const UA_ObjectTypeNode *
 getObjectNodeType(UA_Server *server, const UA_ObjectNode *node) {
-    UA_NodeId otId;
-    getNodeType(server, (const UA_Node*)node, &otId);
-
-    const UA_Node *ot = UA_NodeStore_get(server->nodestore, &otId);
+    const UA_NodeId *otId = getNodeType(server, (const UA_Node*)node);
+    const UA_Node *ot = UA_NodeStore_get(server->nodestore, otId);
     if(!ot || ot->nodeClass != UA_NODECLASS_OBJECTTYPE) {
-        ot = NULL;
         UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER,
                      "No ObjectType for the node found");
+        return NULL;
     }
     return (const UA_ObjectTypeNode*)ot;
 }
@@ -198,6 +196,108 @@ UA_Node_hasSubTypeOrInstances(const UA_Node *node) {
     return false;
 }
 
+static const UA_NodeId hasSubtypeNodeId =
+    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
+
+static UA_StatusCode
+getTypeHierarchyFromNode(UA_NodeId **results_ptr, size_t *results_count,
+                         size_t *results_size, const UA_Node *node) {
+    UA_NodeId *results = *results_ptr;
+    for(size_t i = 0; i < node->referencesSize; ++i) {
+        /* Is the reference kind relevant? */
+        UA_NodeReferenceKind *refs = &node->references[i];
+        if(!refs->isInverse)
+            continue;
+        if(!UA_NodeId_equal(&hasSubtypeNodeId, &refs->referenceTypeId))
+            continue;
+
+        /* Append all targets of the reference kind .. if not a duplicate */
+        for(size_t j = 0; j < refs->targetIdsSize; ++j) {
+            /* Is the target a duplicate? (multi-inheritance) */
+            UA_NodeId *targetId = &refs->targetIds[j].nodeId;
+            UA_Boolean duplicate = false;
+            for(size_t k = 0; k < *results_count; ++k) {
+                if(UA_NodeId_equal(targetId, &results[k])) {
+                    duplicate = true;
+                    break;
+                }
+            }
+            if(duplicate)
+                continue;
+
+            /* Increase array length if necessary */
+            if(*results_count >= *results_size) {
+                size_t new_size = sizeof(UA_NodeId) * (*results_size) * 2;
+                UA_NodeId *new_results = (UA_NodeId*)UA_realloc(results, new_size);
+                if(!new_results) {
+                    UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]);
+                    return UA_STATUSCODE_BADOUTOFMEMORY;
+                }
+                results = new_results;
+                *results_ptr = results;
+                *results_size *= 2;
+            }
+
+            /* Copy new nodeid to the end of the list */
+            UA_StatusCode retval = UA_NodeId_copy(targetId, &results[*results_count]);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]);
+                return retval;
+            }
+            *results_count += 1;
+        }
+    }
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+getTypeHierarchy(UA_NodeStore *ns, const UA_NodeId *leafType,
+                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
+    /* Allocate the results array. Probably too big, but saves mallocs. */
+    size_t results_size = 20;
+    UA_NodeId *results = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * results_size);
+    if(!results)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    /* The leaf is the first element */
+    size_t results_count = 1;
+    UA_StatusCode retval = UA_NodeId_copy(leafType, &results[0]);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_free(results);
+        return retval;
+    }
+
+    /* Loop over the array members .. and add new elements to the end */
+    for(size_t idx = 0; idx < results_count; ++idx) {
+        /* Get the node */
+        const UA_Node *node = UA_NodeStore_get(ns, &results[idx]);
+
+        /* Invalid node, remove from the array */
+        if(!node) {
+            for(size_t i = idx; i < results_count-1; ++i)
+                results[i] = results[i+1];
+            results_count--;
+            continue;
+        }
+
+        /* Add references from the current node to the end of the array */
+        retval = getTypeHierarchyFromNode(&results, &results_count,
+                                          &results_size, node);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* Zero results. The leaf node was not found */
+    if(results_count == 0) {
+        UA_free(results);
+        results = NULL;
+    }
+
+    *typeHierarchy = results;
+    *typeHierarchySize = results_count;
+    return UA_STATUSCODE_GOOD;
+}
+
 /* For mulithreading: make a copy of the node, edit and replace.
  * For singletrheading: edit the original */
 UA_StatusCode

+ 22 - 100
src/server/ua_services_nodemanagement.c

@@ -176,8 +176,8 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
                       const UA_VariableNode *node,
                       const UA_NodeId *typeDef) {
     /* Get the variable type */
-    const UA_VariableTypeNode *vt =
-        (const UA_VariableTypeNode*)UA_NodeStore_get(server->nodestore, typeDef);
+    const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)
+        UA_NodeStore_get(server->nodestore, typeDef);
     if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE)
         return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
     if(node->nodeClass == UA_NODECLASS_VARIABLE && vt->isAbstract)
@@ -248,87 +248,6 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
 /* Instantiate Node */
 /********************/
 
-/* Returns an array with all subtype nodeids (including the root). Supertypes
- * need to have the same nodeClass as root and are (recursively) related with a
- * hasSubType reference. Since multi-inheritance is possible, we test for
- * duplicates and return evey nodeid at most once. */
-static UA_StatusCode
-getTypeHierarchy(UA_NodeStore *ns, const UA_Node *rootRef,
-                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
-    size_t results_size = 20; // probably too big, but saves mallocs
-    UA_NodeId *results = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * results_size);
-    if(!results)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-
-    UA_StatusCode retval = UA_NodeId_copy(&rootRef->nodeId, &results[0]);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_free(results);
-        return retval;
-    }
-
-    const UA_Node *node = rootRef;
-    size_t idx = 0; /* Current index (contains NodeId of node) */
-    size_t last = 0; /* Index of the last element in the array */
-    const UA_NodeId hasSubtypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
-    while(true) {
-        for(size_t i = 0; i < node->referencesSize; ++i) {
-            UA_NodeReferenceKind *refs = &node->references[i];
-            /* Are the references relevant? */
-            if(!refs->isInverse)
-                continue;
-            if(!UA_NodeId_equal(&hasSubtypeNodeId, &refs->referenceTypeId))
-                continue;
-
-            for(size_t j = 0; j < refs->targetIdsSize; ++j) {
-                UA_NodeId *targetId = &refs->targetIds[j].nodeId;
-
-                /* Is the target already considered? (multi-inheritance) */
-                UA_Boolean duplicate = false;
-                for(size_t k = 0; k <= last; ++k) {
-                    if(UA_NodeId_equal(targetId, &results[k])) {
-                        duplicate = true;
-                        break;
-                    }
-                }
-                if(duplicate)
-                    continue;
-
-                /* Increase array length if necessary */
-                if(last + 1 >= results_size) {
-                    UA_NodeId *new_results =
-                        (UA_NodeId*)UA_realloc(results, sizeof(UA_NodeId) * results_size * 2);
-                    if(!new_results) {
-                        UA_Array_delete(results, last, &UA_TYPES[UA_TYPES_NODEID]);
-                        return UA_STATUSCODE_BADOUTOFMEMORY;
-                    }
-                    results = new_results;
-                    results_size *= 2;
-                }
-
-                /* Copy new nodeid to the end of the list */
-                retval = UA_NodeId_copy(targetId, &results[++last]);
-                if(retval != UA_STATUSCODE_GOOD) {
-                    UA_Array_delete(results, last, &UA_TYPES[UA_TYPES_NODEID]);
-                    return retval;
-                }
-            }
-        }
-
-        /* Get the next node */
-    next:
-        ++idx;
-        if(idx > last || retval != UA_STATUSCODE_GOOD)
-            break;
-        node = UA_NodeStore_get(ns, &results[idx]);
-        if(!node || node->nodeClass != rootRef->nodeClass)
-            goto next;
-    }
-
-    *typeHierarchy = results;
-    *typeHierarchySize = last + 1;
-    return UA_STATUSCODE_GOOD;
-}
-
 static UA_StatusCode
 setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* node,
                         void * (*constructor)(const UA_NodeId instance)) {
@@ -375,11 +294,13 @@ instanceFindAggregateByBrowsename(UA_Server *server, UA_Session *session,
     return retval;
 }
 
+const UA_NodeId mandatoryId =
+    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_MODELLINGRULE_MANDATORY}};
+const UA_NodeId hasModellingRuleId =
+    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASMODELLINGRULE}};
+
 static UA_Boolean
 isMandatoryChild(UA_Server *server, UA_Session *session, const UA_NodeId *childNodeId) {
-    const UA_NodeId mandatoryId = UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY);
-    const UA_NodeId hasModellingRuleId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE);
-
     /* Get the child */
     const UA_Node *child = UA_NodeStore_get(server->nodestore, childNodeId);
     if(!child)
@@ -439,36 +360,37 @@ copyChildNode(UA_Server *server, UA_Session *session,
         addReference(server, session, &newItem, &retval);
     } else if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
               rd->nodeClass == UA_NODECLASS_OBJECT) {
-        /* Copy the node */
-        UA_Node *node = UA_NodeStore_getCopy(server->nodestore, &rd->nodeId.nodeId);
+        /* Get the original node */
+        const UA_Node *node = UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
         if(!node)
             return UA_STATUSCODE_BADNODEIDINVALID;
 
         /* Get the type */
-        UA_NodeId typeId;
-        getNodeType(server, node, &typeId);
+        const UA_NodeId *typeId = getNodeType(server, node);
+
+        /* Copy the node */
+        UA_Node *node_copy = UA_NodeStore_getCopy(server->nodestore, &rd->nodeId.nodeId);
+        if(!node_copy)
+            return UA_STATUSCODE_BADNODEIDINVALID;
 
         /* Reset the NodeId (random numeric id will be assigned in the nodestore) */
-        UA_NodeId_deleteMembers(&node->nodeId);
-        node->nodeId.namespaceIndex = destinationNodeId->namespaceIndex;
+        UA_NodeId_deleteMembers(&node_copy->nodeId);
+        node_copy->nodeId.namespaceIndex = destinationNodeId->namespaceIndex;
 
         /* Remove references, they are re-created from scratch in addnode_finish */
         /* TODO: Be more clever in removing references that are re-added during
          * addnode_finish. That way, we can call addnode_finish also on children that were
          * manually added by the user during addnode_begin and addnode_finish. */
-        UA_Node_deleteReferences(node);
+        UA_Node_deleteReferences(node_copy);
 
         /* Add the node to the nodestore */
-        retval = UA_NodeStore_insert(server->nodestore, node);
+        retval = UA_NodeStore_insert(server->nodestore, node_copy);
 
         /* Call addnode_finish, this recursively adds members, the type definition and so on */
         if(retval == UA_STATUSCODE_GOOD)
-            retval = Service_AddNode_finish(server, session, &node->nodeId,
+            retval = Service_AddNode_finish(server, session, &node_copy->nodeId,
                                             destinationNodeId, &rd->referenceTypeId,
-                                            &typeId, instantiationCallback);
-
-        /* Clean up */
-        UA_NodeId_deleteMembers(&typeId);
+                                            typeId, instantiationCallback);
     }
     return retval;
 }
@@ -535,7 +457,7 @@ instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
     /* Get the hierarchy of the type and all its supertypes */
     UA_NodeId *hierarchy = NULL;
     size_t hierarchySize = 0;
-    UA_StatusCode retval = getTypeHierarchy(server->nodestore, typenode,
+    UA_StatusCode retval = getTypeHierarchy(server->nodestore, typeId,
                                             &hierarchy, &hierarchySize);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;

+ 2 - 3
src/server/ua_services_view.c

@@ -24,9 +24,8 @@ fillReferenceDescription(UA_Server *server, const UA_Node *curr,
     if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
         if(curr->nodeClass == UA_NODECLASS_OBJECT ||
            curr->nodeClass == UA_NODECLASS_VARIABLE) {
-            UA_NodeId type;
-            getNodeType(server, curr , &type);
-            retval |= UA_NodeId_copy(&type, &descr->typeDefinition.nodeId);
+            retval |= UA_NodeId_copy(getNodeType(server, curr),
+                                     &descr->typeDefinition.nodeId);
         }
     }
     return retval;