Ver código fonte

Fix #1363 also inherit modeling rules and node values of intermediate types

Stefan Profanter 7 anos atrás
pai
commit
97febf360f

+ 1 - 3
src/server/ua_nodes.c

@@ -573,9 +573,7 @@ UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item) {
 void UA_Node_deleteReferences(UA_Node *node) {
     for(size_t i = 0; i < node->referencesSize; ++i) {
         UA_NodeReferenceKind *refs = &node->references[i];
-        for(size_t j = 0; j < refs->targetIdsSize; ++j)
-            UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]);
-        UA_free(refs->targetIds);
+        UA_Array_delete(refs->targetIds, refs->targetIdsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
         UA_NodeId_deleteMembers(&refs->referenceTypeId);
     }
     if(node->references)

+ 82 - 3
src/server/ua_services_nodemanagement.c

@@ -335,6 +335,77 @@ static void
 addReference(UA_Server *server, UA_Session *session,
              const UA_AddReferencesItem *item, UA_StatusCode *retval);
 
+
+/*
+ * This method only deletes references from the node which are not matching any type in the given array.
+ * Could be used to e.g. delete all the references, except 'HASMODELINGRULE'
+ */
+static void deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, UA_NodeId* referencesSkip) {
+    if (referencesSkipSize == 0) {
+        UA_Node_deleteReferences(node);
+        return;
+    }
+
+    /* Let's count if there are references left. If not just delete all the references.
+     * It's faster */
+    size_t newSize = 0;
+    for(size_t i = 0; i < node->referencesSize; ++i) {
+        for (size_t j = 0; j < referencesSkipSize; j++) {
+            if (UA_NodeId_equal(&node->references[i].referenceTypeId, &referencesSkip[j])) {
+                newSize++;
+            }
+        }
+    }
+    if (newSize == 0){
+        UA_Node_deleteReferences(node);
+        return;
+    }
+
+    /* Now copy the remaining references to a new array */
+    UA_NodeReferenceKind *newReferences = (UA_NodeReferenceKind *)UA_malloc(sizeof(UA_NodeReferenceKind) * (newSize));
+    size_t curr = 0;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    for(size_t i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; ++i) {
+        for (size_t j = 0; j < referencesSkipSize; j++) {
+            if (!UA_NodeId_equal(&node->references[i].referenceTypeId, &referencesSkip[j]))
+                continue;
+
+            // copy the reference
+            UA_NodeReferenceKind *srefs = &node->references[i];
+            UA_NodeReferenceKind *drefs = &newReferences[curr++];
+            drefs->isInverse = srefs->isInverse;
+            retval = UA_NodeId_copy(&srefs->referenceTypeId, &drefs->referenceTypeId);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+            retval = UA_Array_copy(srefs->targetIds, srefs->targetIdsSize,
+                                   (void**)&drefs->targetIds,
+                                   &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+            drefs->targetIdsSize = srefs->targetIdsSize;
+            break;
+        }
+        if (retval != UA_STATUSCODE_GOOD) {
+            for (size_t k=0; k<i; k++) {
+                UA_NodeReferenceKind *refs = &newReferences[i];
+                for(size_t j = 0; j < refs->targetIdsSize; ++j)
+                    UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]);
+                UA_Array_delete(refs->targetIds, refs->targetIdsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
+                UA_NodeId_deleteMembers(&refs->referenceTypeId);
+            }
+        }
+    }
+
+    UA_Node_deleteReferences(node);
+    if (retval == UA_STATUSCODE_GOOD) {
+        node->references = newReferences;
+        node->referencesSize = newSize;
+    } else {
+        UA_free(newReferences);
+    }
+}
+
+
 static UA_StatusCode
 copyChildNode(UA_Server *server, UA_Session *session,
               const UA_NodeId *destinationNodeId,
@@ -399,7 +470,9 @@ copyChildNode(UA_Server *server, UA_Session *session,
         /* 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);
+        /* For now we keep all the modelling rule references and delete all others */
+        UA_NodeId modellingRuleReferenceId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE);
+        deleteReferencesSubset(node, 1, &modellingRuleReferenceId);
 
         /* Add the node to the nodestore */
         UA_NodeId newNodeId;
@@ -409,8 +482,14 @@ copyChildNode(UA_Server *server, UA_Session *session,
             return retval;
         }
 
-        /* Call addnode_finish, this recursively adds members, the type
-         * definition and so on */
+        /* 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.
+         */
+        copyChildNodes(server, session, &rd->nodeId.nodeId, &newNodeId);
+
+        /* 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);
         UA_NodeId_deleteMembers(&newNodeId);

+ 1 - 0
tests/server/check_node_inheritance.c

@@ -186,6 +186,7 @@ START_TEST(Nodes_checkInheritedValue)
         UA_UInt32 *value = (UA_UInt32 *) inheritedValue.data;
 
         ck_assert_int_eq(*value, valueToBeInherited);
+        UA_Variant_deleteMembers(&inheritedValue);
     }
 END_TEST