Browse Source

Add public UA_Server_browseSimplifiedBrowsePath method

Julius Pfrommer 6 years ago
parent
commit
f3a44a96f6
3 changed files with 98 additions and 16 deletions
  1. 13 0
      include/ua_server.h
  2. 71 16
      src/server/ua_services_view.c
  3. 14 0
      tests/server/check_services_view.c

+ 13 - 0
include/ua_server.h

@@ -428,6 +428,19 @@ UA_BrowsePathResult UA_EXPORT
 UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
                                        const UA_BrowsePath *browsePath);
 
+/* A simplified TranslateBrowsePathsToNodeIds based on the
+ * SimpleAttributeOperand type (Part 4, 7.4.4.5).
+ *
+ * This specifies a relative path using a list of BrowseNames instead of the
+ * RelativePath structure. The list of BrowseNames is equivalent to a
+ * RelativePath that specifies forward references which are subtypes of the
+ * HierarchicalReferences ReferenceType. All Nodes followed by the browsePath
+ * shall be of the NodeClass Object or Variable. */
+UA_BrowsePathResult UA_EXPORT
+UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
+                                     size_t browsePathSize,
+                                     const UA_QualifiedName *browsePath);
+
 #ifndef HAVE_NODEITER_CALLBACK
 #define HAVE_NODEITER_CALLBACK
 /* Iterate over all nodes referenced by parentNodeId by calling the callback

+ 71 - 16
src/server/ua_services_view.c

@@ -19,6 +19,10 @@
 #include "ua_server_internal.h"
 #include "ua_services.h"
 
+/**********/
+/* Browse */
+/**********/
+
 /* Target node on top of the stack */
 static UA_StatusCode
 fillReferenceDescription(UA_Server *server, const UA_Node *curr,
@@ -68,6 +72,14 @@ relevantReference(UA_Server *server, UA_Boolean includeSubtypes,
     return isNodeInTree(&server->config.nodestore, testRef, rootRef, &hasSubType, 1);
 }
 
+static UA_Boolean
+matchClassMask(const UA_Node *node, UA_UInt32 nodeClassMask) {
+    if(nodeClassMask != UA_NODECLASS_UNSPECIFIED &&
+       (node->nodeClass & nodeClassMask) == 0)
+        return false;
+    return true;
+}
+
 /* Returns whether the node / continuationpoint is done */
 static UA_Boolean
 browseReferences(UA_Server *server, const UA_Node *node,
@@ -133,7 +145,7 @@ browseReferences(UA_Server *server, const UA_Node *node,
                 continue;
 
             /* Test if the node class matches */
-            if(descr->nodeClassMask != 0 && (target->nodeClass & descr->nodeClassMask) == 0) {
+            if(!matchClassMask(target, descr->nodeClassMask)) {
                 UA_Nodestore_release(server, target);
                 continue;
             }
@@ -445,7 +457,7 @@ walkBrowsePathElementReferenceTargets(UA_BrowsePathResult *result, size_t *targe
 }
 
 static void
-walkBrowsePathElement(UA_Server *server, UA_Session *session,
+walkBrowsePathElement(UA_Server *server, UA_Session *session, UA_UInt32 nodeClassMask,
                       UA_BrowsePathResult *result, size_t *targetsSize,
                       const UA_RelativePathElement *elem, UA_UInt32 elemDepth,
                       const UA_QualifiedName *targetName,
@@ -474,8 +486,14 @@ walkBrowsePathElement(UA_Server *server, UA_Session *session,
             continue;
         }
 
-        /* Test whether the current node has the target name required in the
-         * previous path element */
+        /* Test whether the node fits the class mask */
+        if(!matchClassMask(node, nodeClassMask)) {
+            UA_Nodestore_release(server, node);
+            continue;
+        }
+
+        /* Test whether the node has the target name required in the previous
+         * path element */
         if(targetName && (targetName->namespaceIndex != node->browseName.namespaceIndex ||
                           !UA_String_equal(&targetName->name, &node->browseName.name))) {
             UA_Nodestore_release(server, node);
@@ -507,7 +525,7 @@ walkBrowsePathElement(UA_Server *server, UA_Session *session,
 
 /* This assumes that result->targets has enough room for all currentCount elements */
 static void
-addBrowsePathTargets(UA_Server *server, UA_Session *session,
+addBrowsePathTargets(UA_Server *server, UA_Session *session, UA_UInt32 nodeClassMask,
                      UA_BrowsePathResult *result, const UA_QualifiedName *targetName,
                      UA_NodeId *current, size_t currentCount) {
     for(size_t i = 0; i < currentCount; i++) {
@@ -517,14 +535,18 @@ addBrowsePathTargets(UA_Server *server, UA_Session *session,
             continue;
         }
 
-        /* Test whether the current node has the target name required in the
+        /* Test whether the node fits the class mask */
+        UA_Boolean skip = !matchClassMask(node, nodeClassMask);
+
+        /* Test whether the node has the target name required in the
          * previous path element */
-        UA_Boolean valid = targetName->namespaceIndex == node->browseName.namespaceIndex &&
-            UA_String_equal(&targetName->name, &node->browseName.name);
+        if(targetName->namespaceIndex != node->browseName.namespaceIndex ||
+           !UA_String_equal(&targetName->name, &node->browseName.name))
+            skip = true;
 
         UA_Nodestore_release(server, node);
 
-        if(!valid) {
+        if(skip) {
             UA_NodeId_deleteMembers(&current[i]);
             continue;
         }
@@ -539,7 +561,7 @@ addBrowsePathTargets(UA_Server *server, UA_Session *session,
 
 static void
 walkBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
-               UA_BrowsePathResult *result, size_t targetsSize,
+               UA_UInt32 nodeClassMask, UA_BrowsePathResult *result, size_t targetsSize,
                UA_NodeId **current, size_t *currentSize, size_t *currentCount,
                UA_NodeId **next, size_t *nextSize, size_t *nextCount) {
     UA_assert(*currentCount == 1);
@@ -551,7 +573,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path
     /* Iterate over path elements */
     UA_assert(path->relativePath.elementsSize > 0);
     for(UA_UInt32 i = 0; i < path->relativePath.elementsSize; ++i) {
-        walkBrowsePathElement(server, session, result, &targetsSize,
+        walkBrowsePathElement(server, session, nodeClassMask, result, &targetsSize,
                               &path->relativePath.elements[i], i, targetName,
                               *current, *currentCount, next, nextSize, nextCount);
 
@@ -599,13 +621,13 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path
     }
 
     /* Move the elements of current to the targets */
-    addBrowsePathTargets(server, session, result, targetName, *current, *currentCount);
+    addBrowsePathTargets(server, session, nodeClassMask, result, targetName, *current, *currentCount);
     *currentCount = 0;
 }
 
 static void
 Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session,
-                                       void *context, const UA_BrowsePath *path,
+                                       UA_UInt32 *nodeClassMask, const UA_BrowsePath *path,
                                        UA_BrowsePathResult *result) {
     if(path->relativePath.elementsSize <= 0) {
         result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
@@ -662,7 +684,7 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session,
     currentCount = 1;
 
     /* Walk the path elements */
-    walkBrowsePath(server, session, path, result, targetsSize,
+    walkBrowsePath(server, session, path, *nodeClassMask, result, targetsSize,
                    &current, &currentSize, &currentCount,
                    &next, &nextSize, &nextCount);
 
@@ -690,7 +712,9 @@ UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
                                        const UA_BrowsePath *browsePath) {
     UA_BrowsePathResult result;
     UA_BrowsePathResult_init(&result);
-    Operation_TranslateBrowsePathToNodeIds(server, &adminSession, NULL, browsePath, &result);
+    UA_UInt32 nodeClassMask = 0; /* All node classes */
+    Operation_TranslateBrowsePathToNodeIds(server, &adminSession, &nodeClassMask,
+                                           browsePath, &result);
     return result;
 }
 
@@ -707,13 +731,44 @@ Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
         return;
     }
 
+    UA_UInt32 nodeClassMask = 0; /* All node classes */
     response->responseHeader.serviceResult =
         UA_Server_processServiceOperations(server, session,
                                            (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds,
-                                           NULL, &request->browsePathsSize, &UA_TYPES[UA_TYPES_BROWSEPATH],
+                                           &nodeClassMask,
+                                           &request->browsePathsSize, &UA_TYPES[UA_TYPES_BROWSEPATH],
                                            &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
 }
 
+UA_BrowsePathResult
+UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
+                                     size_t browsePathSize, const UA_QualifiedName *browsePath) {
+    /* Construct the BrowsePath */
+    UA_BrowsePath bp;
+    UA_BrowsePath_init(&bp);
+    bp.startingNode = origin;
+    UA_STACKARRAY(UA_RelativePathElement, rpe, browsePathSize);
+    memset(rpe, 0, sizeof(UA_RelativePathElement) * browsePathSize);
+    for(size_t j = 0; j < browsePathSize; j++) {
+        rpe[j].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
+        rpe[j].includeSubtypes = true;
+        rpe[j].targetName = browsePath[j];
+    }
+    bp.relativePath.elements = rpe;
+    bp.relativePath.elementsSize = browsePathSize;
+
+    /* Browse */
+    UA_BrowsePathResult bpr;
+    UA_BrowsePathResult_init(&bpr);
+    UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE;
+    Operation_TranslateBrowsePathToNodeIds(server, &adminSession, &nodeClassMask, &bp, &bpr);
+    return bpr;
+}
+
+/************/
+/* Register */
+/************/
+
 void Service_RegisterNodes(UA_Server *server, UA_Session *session,
                            const UA_RegisterNodesRequest *request,
                            UA_RegisterNodesResponse *response) {

+ 14 - 0
tests/server/check_services_view.c

@@ -173,6 +173,19 @@ START_TEST(Service_TranslateBrowsePathsToNodeIds) {
 }
 END_TEST
 
+START_TEST(BrowseSimplifiedBrowsePath) {
+    UA_QualifiedName objectsName = UA_QUALIFIEDNAME(0, "Objects");
+    UA_BrowsePathResult bpr =
+        UA_Server_browseSimplifiedBrowsePath(server_translate_browse,
+                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+                                             1, &objectsName);
+
+    ck_assert_int_eq(bpr.targetsSize, 1);
+
+    UA_BrowsePathResult_deleteMembers(&bpr);
+}
+END_TEST
+
 static Suite *testSuite_Service_TranslateBrowsePathsToNodeIds(void) {
     Suite *s = suite_create("Service_TranslateBrowsePathsToNodeIds");
     TCase *tc_browse = tcase_create("Browse Service");
@@ -183,6 +196,7 @@ static Suite *testSuite_Service_TranslateBrowsePathsToNodeIds(void) {
     TCase *tc_translate = tcase_create("TranslateBrowsePathsToNodeIds");
     tcase_add_unchecked_fixture(tc_translate, setup_server, teardown_server);
     tcase_add_test(tc_translate, Service_TranslateBrowsePathsToNodeIds);
+    tcase_add_test(tc_translate, BrowseSimplifiedBrowsePath);
 
     suite_add_tcase(s, tc_translate);
     return s;