瀏覽代碼

Stack: Add support for HasInterface reference (Amendment 7)

Stefan Profanter 5 年之前
父節點
當前提交
d0831c7a5f

+ 6 - 0
src/server/ua_server_internal.h

@@ -167,6 +167,12 @@ getTypesHierarchy(void *nsCtx, const UA_NodeId *leafType, size_t leafTypeSize,
                   UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
                   UA_Boolean walkDownwards);
 
+/* Same as getTypeHierarchy aside of the ``hasSubType`` reference, this also includes
+ * the ``hasInterface`` reference */
+UA_StatusCode
+getParentTypeAndInterfaceHierarchy(void *nsCtx, const UA_NodeId *leafType,
+                                   UA_NodeId **typeHierarchy, size_t *typeHierarchySize);
+
 /* Returns the type node from the node on the stack top. The type node is pushed
  * on the stack and returned. */
 const UA_Node * getNodeType(UA_Server *server, const UA_Node *node);

+ 51 - 12
src/server/ua_server_utils.c

@@ -166,19 +166,29 @@ UA_Node_hasSubTypeOrInstances(const UA_Node *node) {
 
 static const UA_NodeId hasSubtypeNodeId =
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
+static const UA_NodeId hasInterfaceNodeId =
+    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASINTERFACE}};
 
+/**
+ * Gets a list of nodeIds which are referenced by this node.
+ * Hereby the list will be filtered to only include references
+ * which are of the given `references` types.
+ */
 static UA_StatusCode
-getTypeHierarchyFromNode(UA_NodeId **results_ptr, size_t *results_count,
+getReferencedNodesWithReferenceType(UA_NodeId **results_ptr, size_t *results_count,
                          size_t *results_size, const UA_Node *node,
-                         UA_Boolean walkDownwards) {
+                         const UA_NodeReferenceKind *references, size_t referencesSize) {
     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 downwards, we do not want inverse, if upwards we want inverse
-        if (walkDownwards == refs->isInverse)
-            continue;
-        if(!UA_NodeId_equal(&hasSubtypeNodeId, &refs->referenceTypeId))
+
+        bool referenceInList = false;
+        for (size_t j=0; j<referencesSize && !referenceInList; j++) {
+            referenceInList = refs->isInverse == references[j].isInverse &&
+                    UA_NodeId_equal(&references[j].referenceTypeId, &refs->referenceTypeId);
+        }
+        if (!referenceInList)
             continue;
 
         /* Append all targets of the reference kind .. if not a duplicate */
@@ -220,10 +230,11 @@ getTypeHierarchyFromNode(UA_NodeId **results_ptr, size_t *results_count,
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode
-getTypeHierarchy(void *nsCtx, const UA_NodeId *leafType,
-                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
-                 UA_Boolean walkDownwards) {
+
+static UA_StatusCode
+getHierarchyForReferenceTypes(void *nsCtx, const UA_NodeId *leafType,
+                              const UA_NodeReferenceKind *references, size_t referencesSize,
+                              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);
@@ -252,8 +263,8 @@ getTypeHierarchy(void *nsCtx, const UA_NodeId *leafType,
         }
 
         /* Add references from the current node to the end of the array */
-        retval = getTypeHierarchyFromNode(&results, &results_count,
-                                          &results_size, node, walkDownwards);
+        retval = getReferencedNodesWithReferenceType(&results, &results_count,
+                                          &results_size, node, references, referencesSize);
 
         /* Release the node */
         UA_Nodestore_releaseNode(nsCtx, node);
@@ -275,6 +286,34 @@ getTypeHierarchy(void *nsCtx, const UA_NodeId *leafType,
     return UA_STATUSCODE_GOOD;
 }
 
+UA_StatusCode
+getTypeHierarchy(void *nsCtx, const UA_NodeId *leafType,
+                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
+                 UA_Boolean walkDownwards) {
+    UA_NodeReferenceKind subtypeRef;
+    // if downwards, we do not want inverse, if upwards we want inverse
+    subtypeRef.isInverse = !walkDownwards;
+    subtypeRef.referenceTypeId = hasSubtypeNodeId;
+
+
+    return getHierarchyForReferenceTypes(nsCtx, leafType,
+            &subtypeRef, 1, typeHierarchy, typeHierarchySize);
+}
+
+UA_StatusCode
+getParentTypeAndInterfaceHierarchy(void *nsCtx, const UA_NodeId *leafType,
+                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
+
+    UA_NodeReferenceKind subtypeRef[2];
+    subtypeRef[0].isInverse = true;
+    subtypeRef[0].referenceTypeId = hasSubtypeNodeId;
+
+    subtypeRef[1].isInverse = false;
+    subtypeRef[1].referenceTypeId = hasInterfaceNodeId;
+
+    return getHierarchyForReferenceTypes(nsCtx, leafType,
+                                         subtypeRef, 2, typeHierarchy, typeHierarchySize);
+}
 
 UA_StatusCode
 getTypesHierarchy(void *nsCtx, const UA_NodeId *leafType, size_t leafTypeSize,

+ 2 - 2
src/server/ua_services_nodemanagement.c

@@ -544,8 +544,8 @@ addTypeChildren(UA_Server *server, UA_Session *session,
     /* Get the hierarchy of the type and all its supertypes */
     UA_NodeId *hierarchy = NULL;
     size_t hierarchySize = 0;
-    UA_StatusCode retval = getTypeHierarchy(server->nsCtx, &type->nodeId,
-                                            &hierarchy, &hierarchySize, false);
+    UA_StatusCode retval = getParentTypeAndInterfaceHierarchy(server->nsCtx, &type->nodeId,
+                                            &hierarchy, &hierarchySize);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 

+ 87 - 2
tests/server/check_node_inheritance.c

@@ -25,7 +25,7 @@ static void teardown(void) {
 #ifdef UA_GENERATED_NAMESPACE_ZERO
 /* finds the NodeId of a StateNumber child of a given node id */
 static void
-findChildId(UA_NodeId stateId, UA_NodeId referenceType,
+findChildId(UA_NodeId parentNode, UA_NodeId referenceType,
             const UA_QualifiedName targetName, UA_NodeId *result) {
     UA_RelativePathElement rpe;
     UA_RelativePathElement_init(&rpe);
@@ -36,7 +36,7 @@ findChildId(UA_NodeId stateId, UA_NodeId referenceType,
 
     UA_BrowsePath bp;
     UA_BrowsePath_init(&bp);
-    bp.startingNode = stateId;
+    bp.startingNode = parentNode;
     bp.relativePath.elementsSize = 1;
     bp.relativePath.elements = &rpe;    //clion complains but is ok
 
@@ -308,6 +308,86 @@ START_TEST(Nodes_checkInheritedValue) {
 END_TEST
 
 
+
+START_TEST(Nodes_createCustomInterfaceType) {
+/* Minimal nodeset does not have the Interface definitions */
+#ifdef UA_GENERATED_NAMESPACE_ZERO
+    /* Create a custom interface type */
+
+    UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.displayName = UA_LOCALIZEDTEXT("", "ILocationType");
+    otAttr.description = UA_LOCALIZEDTEXT("", "");
+    UA_StatusCode retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 8000),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_BASEINTERFACETYPE),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                         UA_QUALIFIEDNAME(1, "ILocationType"),
+                                         otAttr, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.displayName = UA_LOCALIZEDTEXT("", "InterfaceChild");
+    oAttr.description = UA_LOCALIZEDTEXT("", "");
+    retval = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 8001), UA_NODEID_NUMERIC(1, 8000),
+                                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                     UA_QUALIFIEDNAME(1, "InterfaceChild"),
+                                     UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                     oAttr, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 8001),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
+                                    UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY),
+                                    true);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+
+    /* create an object type which has the interface */
+    otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.displayName = UA_LOCALIZEDTEXT("", "ObjectWithLocation");
+    otAttr.description = UA_LOCALIZEDTEXT("", "");
+    retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 8002),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                         UA_QUALIFIEDNAME(1, "ObjectWithLocation"),
+                                         otAttr, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 8002), UA_NODEID_NUMERIC(0, UA_NS0ID_HASINTERFACE), UA_EXPANDEDNODEID_NUMERIC(1, 8000), true);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+#endif
+}
+END_TEST
+
+
+
+START_TEST(Nodes_createObjectWithInterface) {
+
+/* Minimal nodeset does not have the Interface definitions */
+#ifdef UA_GENERATED_NAMESPACE_ZERO
+    /* create an object/instance of the demo type */
+    UA_ObjectAttributes oAttr2 = UA_ObjectAttributes_default;
+    oAttr2.displayName = UA_LOCALIZEDTEXT("", "ObjectInstanceOfInterface");
+    oAttr2.description = UA_LOCALIZEDTEXT("", "");
+    UA_StatusCode retval =
+            UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 8020),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                    UA_QUALIFIEDNAME(1, "ObjectInstanceOfInterface"), UA_NODEID_NUMERIC(1, 8002),
+                                    oAttr2, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+
+    /* Check that object has inherited the interface children */
+
+    UA_NodeId childId;
+    findChildId(UA_NODEID_NUMERIC(1, 8020),
+                UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                UA_QUALIFIEDNAME(1, "InterfaceChild"), &childId);
+    ck_assert(!UA_NodeId_isNull(&childId));
+#endif
+}
+END_TEST
+
 static Suite *testSuite_Client(void) {
     Suite *s = suite_create("Node inheritance");
     TCase *tc_inherit_subtype = tcase_create("Inherit subtype value");
@@ -319,6 +399,11 @@ static Suite *testSuite_Client(void) {
     tcase_add_test(tc_inherit_subtype, Nodes_createCustomBrowseNameObjectType);
     tcase_add_test(tc_inherit_subtype, Nodes_checkDefaultInstanceBrowseName);
     suite_add_tcase(s, tc_inherit_subtype);
+    TCase *tc_interface_addin = tcase_create("Interfaces and Addins");
+    tcase_add_unchecked_fixture(tc_interface_addin, setup, teardown);
+    tcase_add_test(tc_interface_addin, Nodes_createCustomInterfaceType);
+    tcase_add_test(tc_interface_addin, Nodes_createObjectWithInterface);
+    suite_add_tcase(s, tc_interface_addin);
     return s;
 }