Browse Source

Stack: Add support for DefaultInstanceBrowseName (see Amendment 7)

Stefan Profanter 5 years ago
parent
commit
857c2bc421

+ 78 - 0
src/server/ua_services_nodemanagement.c

@@ -924,6 +924,80 @@ recursiveTypeCheckAddChildren(UA_Server *server, UA_Session *session,
     return UA_STATUSCODE_GOOD;
 }
 
+static UA_StatusCode
+findDefaultInstanceBrowseNameNode(UA_Server *server,
+                    UA_NodeId startingNode, UA_NodeId *foundId){
+
+    UA_NodeId_init(foundId);
+    UA_RelativePathElement rpe;
+    UA_RelativePathElement_init(&rpe);
+    rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
+    rpe.isInverse = false;
+    rpe.includeSubtypes = false;
+    rpe.targetName = UA_QUALIFIEDNAME(0, "DefaultInstanceBrowseName");
+    UA_BrowsePath bp;
+    UA_BrowsePath_init(&bp);
+    bp.startingNode = startingNode;
+    bp.relativePath.elementsSize = 1;
+    bp.relativePath.elements = &rpe;
+    UA_BrowsePathResult bpr =
+            UA_Server_translateBrowsePathToNodeIds(server, &bp);
+    UA_StatusCode retval = bpr.statusCode;
+    if (retval == UA_STATUSCODE_GOOD &&
+        bpr.targetsSize > 0) {
+        retval = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, foundId);
+    }
+    UA_BrowsePathResult_deleteMembers(&bpr);
+    return retval;
+}
+
+/* Check if we got a valid browse name for the new node.
+ * For object nodes the BrowseName may only be null if the parent type has a
+ * 'DefaultInstanceBrowseName' property.
+ * */
+static UA_StatusCode
+checkValidBrowseName(UA_Server *server, UA_Session *session,
+                     const UA_Node *node, const UA_Node *type) {
+
+    UA_assert(type != NULL);
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+    if(node->nodeClass != UA_NODECLASS_OBJECT) {
+        /* nodes other than Objects must have a browseName */
+        if (UA_QualifiedName_isNull(&node->browseName))
+            return UA_STATUSCODE_BADBROWSENAMEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
+
+    /* If the object node already has a browse name we are done here. */
+    if(!UA_QualifiedName_isNull(&node->browseName))
+        return UA_STATUSCODE_GOOD;
+
+    /* at this point we have an object with an empty browse name.
+     * Check the type node if it has a DefaultInstanceBrowseName property
+     */
+
+    UA_NodeId defaultBrowseNameNode;
+    retval = findDefaultInstanceBrowseNameNode(server, type->nodeId, &defaultBrowseNameNode);
+    if (retval != UA_STATUSCODE_GOOD) {
+        if (retval == UA_STATUSCODE_BADNOMATCH)
+            /* the DefaultBrowseName property is not found, return the corresponding status code */
+            return UA_STATUSCODE_BADBROWSENAMEINVALID;
+        return retval;
+    }
+
+    UA_Variant defaultBrowseName;
+    retval = UA_Server_readValue(server, defaultBrowseNameNode, &defaultBrowseName);
+    if (retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    UA_QualifiedName *defaultValue = (UA_QualifiedName *) defaultBrowseName.data;
+    retval = UA_Server_writeBrowseName(server, node->nodeId, *defaultValue);
+    UA_Variant_clear(&defaultBrowseName);
+
+    return retval;
+}
+
 /* Construct children first */
 static UA_StatusCode
 recursiveCallConstructors(UA_Server *server, UA_Session *session,
@@ -1071,6 +1145,10 @@ AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId)
             goto cleanup;
         }
 
+        retval = checkValidBrowseName(server, session, node, type);
+        if(retval != UA_STATUSCODE_GOOD)
+            goto cleanup;
+
         retval = recursiveTypeCheckAddChildren(server, session, &node, type);
         if(retval != UA_STATUSCODE_GOOD)
             goto cleanup;

+ 2 - 1
src/server/ua_subscription_events.c

@@ -87,7 +87,8 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *o
 
     /* Create an ObjectNode which represents the event */
     UA_QualifiedName name;
-    UA_QualifiedName_init(&name);
+    // set a dummy name. This is not used.
+    name = UA_QUALIFIEDNAME(0,"E");
     UA_NodeId newNodeId = UA_NODEID_NULL;
     UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
     UA_StatusCode retval =

+ 110 - 0
tests/server/check_node_inheritance.c

@@ -50,6 +50,114 @@ findChildId(UA_NodeId stateId, UA_NodeId referenceType,
 }
 #endif
 
+
+
+START_TEST(Nodes_createCustomBrowseNameObjectType)
+{
+    /* Create a custom object type "CustomBrowseNameType" which has a
+     * "DefaultInstanceBrowseName" property. */
+
+    /* create new object type node which has a subcomponent of the type StateType */
+    UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.displayName = UA_LOCALIZEDTEXT("", "CustomBrowseNameType");
+    otAttr.description = UA_LOCALIZEDTEXT("", "");
+    UA_StatusCode retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 7010),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                         UA_QUALIFIEDNAME(1, "CustomBrowseNameType"),
+                                         otAttr, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    // Now add a property "DefaultInstanceBrowseName"
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.minimumSamplingInterval = 0.000000;
+    attr.userAccessLevel = 1;
+    attr.accessLevel = 1;
+    attr.valueRank = UA_VALUERANK_ANY;
+    attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_QUALIFIEDNAME);
+    UA_QualifiedName defaultInstanceBrowseName = UA_QUALIFIEDNAME(1, "MyCustomBrowseName");
+    UA_Variant_setScalar(&attr.value, &defaultInstanceBrowseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+    attr.displayName = UA_LOCALIZEDTEXT("", "DefaultInstanceBrowseName");
+    attr.description = UA_LOCALIZEDTEXT("", "");
+    attr.writeMask = 0;
+    attr.userWriteMask = 0;
+    retval = UA_Server_addVariableNode(server,
+                                       UA_NODEID_NUMERIC(1, 7011),
+                                       UA_NODEID_NUMERIC(1, 7010),
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
+                                       UA_QUALIFIEDNAME(0, "DefaultInstanceBrowseName"),
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
+                                       attr,
+                                       NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+} END_TEST
+
+
+
+START_TEST(Nodes_checkDefaultInstanceBrowseName) {
+    /* create an object/instance of the CustomDemoType.
+     * This should fail if we do not specifiy a browse name.
+     * CustomDemoType does not have a DefaultInstanceBrowseName
+     * */
+    UA_ObjectAttributes oAttr2 = UA_ObjectAttributes_default;
+    oAttr2.displayName = UA_LOCALIZEDTEXT("", "DemoCustomBrowseNameFail");
+    oAttr2.description = UA_LOCALIZEDTEXT("", "");
+    UA_QualifiedName nullName;
+    UA_QualifiedName_init(&nullName);
+    UA_StatusCode retval =
+            UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 7020),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                    nullName, UA_NODEID_NUMERIC(1, 6010),
+                                    oAttr2, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_BADBROWSENAMEINVALID);
+
+    /* create an object/instance of the CustomBrowseNameType and set the default browse name */
+    oAttr2 = UA_ObjectAttributes_default;
+    oAttr2.displayName = UA_LOCALIZEDTEXT("", "DemoCustomBrowseName");
+    oAttr2.description = UA_LOCALIZEDTEXT("", "");
+    UA_QualifiedName_init(&nullName);
+    retval =
+            UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 7021),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                    nullName, UA_NODEID_NUMERIC(1, 7010),
+                                    oAttr2, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_QualifiedName receivedBrowseName;
+    UA_QualifiedName_init(&receivedBrowseName);
+
+    UA_QualifiedName defaultInstanceBrowseName = UA_QUALIFIEDNAME(1, "MyCustomBrowseName");
+
+    retval = UA_Server_readBrowseName(server, UA_NODEID_NUMERIC(1, 7021), &receivedBrowseName);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+    ck_assert(UA_QualifiedName_equal(&receivedBrowseName, &defaultInstanceBrowseName) == true);
+    UA_QualifiedName_clear(&receivedBrowseName);
+
+    /* create an object/instance of the CustomBrowseNameType and set a custom browse name */
+    oAttr2 = UA_ObjectAttributes_default;
+    oAttr2.displayName = UA_LOCALIZEDTEXT("", "DemoCustomBrowseName");
+    oAttr2.description = UA_LOCALIZEDTEXT("", "");
+    UA_QualifiedName overriddenBrowseName = UA_QUALIFIEDNAME(1, "MyOverriddenBrowseName");
+    retval =
+            UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 7022),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                    overriddenBrowseName, UA_NODEID_NUMERIC(1, 7010),
+                                    oAttr2, NULL, NULL);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_QualifiedName_init(&receivedBrowseName);
+
+    retval = UA_Server_readBrowseName(server, UA_NODEID_NUMERIC(1, 7022), &receivedBrowseName);
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+    ck_assert(UA_QualifiedName_equal(&receivedBrowseName, &overriddenBrowseName) == true);
+    UA_QualifiedName_clear(&receivedBrowseName);
+}
+END_TEST
+
 START_TEST(Nodes_createCustomStateType) {
     // Create a type "CustomStateType" with a variable "CustomStateNumber" as property
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
@@ -208,6 +316,8 @@ static Suite *testSuite_Client(void) {
     tcase_add_test(tc_inherit_subtype, Nodes_createCustomObjectType);
     tcase_add_test(tc_inherit_subtype, Nodes_createInheritedObject);
     tcase_add_test(tc_inherit_subtype, Nodes_checkInheritedValue);
+    tcase_add_test(tc_inherit_subtype, Nodes_createCustomBrowseNameObjectType);
+    tcase_add_test(tc_inherit_subtype, Nodes_checkDefaultInstanceBrowseName);
     suite_add_tcase(s, tc_inherit_subtype);
     return s;
 }

+ 4 - 4
tests/server/check_services_nodemanagement.c

@@ -246,7 +246,7 @@ START_TEST(AddObjectWithConstructor) {
     res = UA_Server_addObjectNode(server, UA_NODEID_NULL,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                  UA_QUALIFIEDNAME(0, ""), objecttypeid,
+                                  UA_QUALIFIEDNAME(0, "MyObjectNode"), objecttypeid,
                                   attr2, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
@@ -290,7 +290,7 @@ START_TEST(DeleteObjectWithDestructor) {
     res = UA_Server_addObjectNode(server, objectid,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                  UA_QUALIFIEDNAME(0, ""), objecttypeid,
+                                  UA_QUALIFIEDNAME(0, "MyObject"), objecttypeid,
                                   attr2, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
@@ -310,7 +310,7 @@ START_TEST(DeleteObjectAndReferences) {
     res = UA_Server_addObjectNode(server, objectid,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                  UA_QUALIFIEDNAME(0, ""),
+                                  UA_QUALIFIEDNAME(0, "MyObject"),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                                   attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
@@ -353,7 +353,7 @@ START_TEST(DeleteObjectAndReferences) {
     res = UA_Server_addObjectNode(server, objectid,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                  UA_QUALIFIEDNAME(0, ""),
+                                  UA_QUALIFIEDNAME(0, "MyObject"),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                                   attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);