static size_t browseWithMaxResults(UA_Server *server, UA_NodeId nodeId, UA_UInt32 maxResults) { UA_BrowseDescription bd; UA_BrowseDescription_init(&bd); bd.nodeId = nodeId; bd.resultMask = UA_BROWSERESULTMASK_ALL; bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; UA_BrowseResult br = UA_Server_browse(server, maxResults, &bd); ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD); ck_assert(br.referencesSize > 0); size_t total = br.referencesSize; UA_ByteString cp = br.continuationPoint; br.continuationPoint = UA_BYTESTRING_NULL; UA_BrowseResult_deleteMembers(&br); while(cp.length > 0) { br = UA_Server_browseNext(server, false, &cp); ck_assert(br.referencesSize > 0); UA_ByteString_deleteMembers(&cp); cp = br.continuationPoint; br.continuationPoint = UA_BYTESTRING_NULL; total += br.referencesSize; UA_BrowseResult_deleteMembers(&br); } return total; }
UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, UA_Boolean deleteReferences) { UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId); if(!node) return UA_STATUSCODE_BADNODEIDINVALID; if(deleteReferences == UA_TRUE) { UA_DeleteReferencesItem delItem; UA_DeleteReferencesItem_init(&delItem); delItem.deleteBidirectional = UA_FALSE; delItem.targetNodeId.nodeId = *nodeId; for(size_t i = 0; i < node->referencesSize; i++) { delItem.sourceNodeId = node->references[i].targetId.nodeId; delItem.isForward = node->references[i].isInverse; Service_DeleteReferences_single(server, session, &delItem); } } /* destroy an object before removing it */ if(node->nodeClass == UA_NODECLASS_OBJECT) { /* find the object type(s) */ UA_BrowseDescription bd; UA_BrowseDescription_init(&bd); bd.browseDirection = UA_BROWSEDIRECTION_INVERSE; bd.nodeId = *nodeId; bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); bd.includeSubtypes = UA_TRUE; bd.nodeClassMask = UA_NODECLASS_OBJECTTYPE; /* browse type definitions with admin rights */ UA_BrowseResult result; UA_BrowseResult_init(&result); Service_Browse_single(server, &adminSession, NULL, &bd, UA_UINT32_MAX, &result); for(size_t i = 0; i < result.referencesSize; i++) { /* call the destructor */ UA_ReferenceDescription *rd = &result.references[i]; const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId); if(!type) continue; if(type->nodeClass != UA_NODECLASS_OBJECTTYPE || !type->lifecycleManagement.destructor) continue; /* if there are several types with lifecycle management, call all the destructors */ type->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle); } UA_BrowseResult_deleteMembers(&result); } return UA_NodeStore_remove(server->nodestore, nodeId); }
END_TEST START_TEST(Service_Browse_WithBrowseName) { UA_ServerConfig *config = UA_ServerConfig_new_default(); UA_Server *server = UA_Server_new(config); UA_BrowseDescription bd; UA_BrowseDescription_init(&bd); bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME; bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; UA_BrowseResult br = UA_Server_browse(server, 0, &bd); ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD); ck_assert(br.referencesSize > 0); ck_assert(!UA_String_equal(&br.references[0].browseName.name, &UA_STRING_NULL)); UA_BrowseResult_deleteMembers(&br); UA_Server_delete(server); UA_ServerConfig_delete(config); }
} END_TEST START_TEST(DeleteObjectAndReferences) { /* Add an object of the type */ UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("en-US","my object"); UA_NodeId objectid = UA_NODEID_NUMERIC(0, 23372337); UA_StatusCode res; res = UA_Server_addObjectNode(server, objectid, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(0, ""), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), attr, NULL, NULL); ck_assert_int_eq(res, UA_STATUSCODE_GOOD); /* Verify that we have a reference to the node from the objects folder */ UA_BrowseDescription bd; UA_BrowseDescription_init(&bd); bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; UA_BrowseResult br = UA_Server_browse(server, 0, &bd); ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD); size_t refCount = 0; for(size_t i = 0; i < br.referencesSize; ++i) { if(UA_NodeId_equal(&br.references[i].nodeId.nodeId, &objectid)) refCount++; } ck_assert_int_eq(refCount, 1); UA_BrowseResult_deleteMembers(&br); /* Delete the object */ UA_Server_deleteNode(server, objectid, true); /* Browse again, this time we expect that no reference is found */ br = UA_Server_browse(server, 0, &bd); ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD); refCount = 0; for(size_t i = 0; i < br.referencesSize; ++i) { if(UA_NodeId_equal(&br.references[i].nodeId.nodeId, &objectid)) refCount++; } ck_assert_int_eq(refCount, 0); UA_BrowseResult_deleteMembers(&br); /* Add an object the second time */ attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("en-US","my object"); objectid = UA_NODEID_NUMERIC(0, 23372337); res = UA_Server_addObjectNode(server, objectid, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(0, ""), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), attr, NULL, NULL); ck_assert_int_eq(res, UA_STATUSCODE_GOOD); /* Browse again, this time we expect that a single reference to the node is found */ refCount = 0; br = UA_Server_browse(server, 0, &bd); ck_assert_int_eq(br.statusCode, UA_STATUSCODE_GOOD); for(size_t i = 0; i < br.referencesSize; ++i) { if(UA_NodeId_equal(&br.references[i].nodeId.nodeId, &objectid)) refCount++; } ck_assert_int_eq(refCount, 1); UA_BrowseResult_deleteMembers(&br); } END_TEST