Browse Source

View: BrowseRecursive returns only ExpandedNodeIds; Simplify

The reference type in the full BrowseDescription is meaningless.
This is only a local API. So it is easy/fast to look up more attributes.
Julius Pfrommer 4 years ago
parent
commit
c5f41e12d2

+ 7 - 9
include/open62541/server.h

@@ -458,19 +458,17 @@ UA_BrowseResult UA_EXPORT
 UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences,
                  const UA_BrowseDescription *bd);
 
-/* Nonstandard version of the browse service that recurses into child nodes.
- * Possible loops (that can occur for non-hierarchical references) are handled
- * by adding every target node at most once to the result array. The returned
- * ReferenceDescription refers has the `ReferenceTypeId` and `IsForward` fields
- * set according to the last reference in the (recursive) chain. */
-UA_BrowseResult UA_EXPORT
-UA_Server_browseRecursive(UA_Server *server, UA_UInt32 maxReferences,
-                          const UA_BrowseDescription *bd);
-
 UA_BrowseResult UA_EXPORT
 UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
                      const UA_ByteString *continuationPoint);
 
+/* Nonstandard version of the browse service that recurses into child nodes.
+ * Possible loops (that can occur for non-hierarchical references) are handled
+ * by adding every target node at most once to the results array. */
+UA_StatusCode UA_EXPORT
+UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
+                          size_t *resultsSize, UA_ExpandedNodeId *results);
+
 UA_BrowsePathResult UA_EXPORT
 UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
                                        const UA_BrowsePath *browsePath);

+ 11 - 4
src/server/ua_server_internal.h

@@ -153,9 +153,16 @@ isNodeInTree(void *nsCtx, const UA_NodeId *leafNode,
  * "downwards". Duplicate entries are removed. The parameter `walkDownwards`
  * indicates the direction of search. */
 UA_StatusCode
-getLocalRecursiveHierarchy(UA_Server *server, const UA_NodeId *startNodes, size_t startNodesSize,
-                           const UA_NodeId *refTypes, size_t refTypesSize, UA_Boolean walkDownwards,
-                           UA_NodeId **results, size_t *resultsSize);
+browseRecursive(UA_Server *server,
+                size_t startNodesSize, const UA_NodeId *startNodes,
+                size_t refTypesSize, const UA_NodeId *refTypes,
+                UA_BrowseDirection browseDirection, UA_Boolean includeStartNodes,
+                size_t *resultsSize, UA_ExpandedNodeId **results);
+
+/* If refTypes is non-NULL, tries to realloc and increase the length */
+UA_StatusCode
+referenceSubtypes(UA_Server *server, const UA_NodeId *refType,
+                  size_t *refTypesSize, UA_NodeId **refTypes);
 
 /* Returns the recursive type and interface hierarchy of the node */ 
 UA_StatusCode
@@ -245,7 +252,7 @@ struct BrowseOpts {
 };
 
 void
-Operation_Browse(UA_Server *server, UA_Session *session, const struct BrowseOpts *maxrefs,
+Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxrefs,
                  const UA_BrowseDescription *descr, UA_BrowseResult *result);
 
 UA_DataValue

+ 41 - 17
src/server/ua_server_utils.c

@@ -170,36 +170,60 @@ static const UA_NodeId hasInterfaceNodeId =
 UA_StatusCode
 getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode,
                                    UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
-    UA_NodeId *subTypes = NULL;
+    UA_ExpandedNodeId *subTypes = NULL;
     size_t subTypesSize = 0;
-    UA_StatusCode retval =
-        getLocalRecursiveHierarchy(server, typeNode, 1, &subtypeId, 1,
-                                   false, &subTypes, &subTypesSize);
+    UA_StatusCode retval = browseRecursive(server, 1, typeNode, 1, &subtypeId,
+                                           UA_BROWSEDIRECTION_INVERSE, false,
+                                           &subTypesSize, &subTypes);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    UA_NodeId *interfaces = NULL;
+    UA_assert(subTypesSize < 1000);
+
+    UA_ExpandedNodeId *interfaces = NULL;
     size_t interfacesSize = 0;
-    retval = getLocalRecursiveHierarchy(server, typeNode, 1, &hasInterfaceNodeId, 1,
-                                        true, &interfaces, &interfacesSize);
+    retval = browseRecursive(server, 1, typeNode, 1, &hasInterfaceNodeId,
+                             UA_BROWSEDIRECTION_FORWARD, false,
+                             &interfacesSize, &interfaces);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
         return retval;
     }
 
-    UA_NodeId *total = (UA_NodeId*)
-        UA_realloc(subTypes, sizeof(UA_NodeId)*(subTypesSize + interfacesSize - 1));
-    if(!total) {
-        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
-        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
+    UA_assert(interfacesSize < 1000);
+
+    UA_NodeId *hierarchy = (UA_NodeId*)
+        UA_malloc(sizeof(UA_NodeId) * (1 + subTypesSize + interfacesSize));
+    if(!hierarchy) {
+        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
+        UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
-    memcpy(&total[subTypesSize], &interfaces[1], sizeof(UA_NodeId)*(interfacesSize-1));
-    UA_free(interfaces);
-    
-    *typeHierarchy = total;
-    *typeHierarchySize = subTypesSize + interfacesSize - 1;
+    retval = UA_NodeId_copy(typeNode, hierarchy);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_free(hierarchy);
+        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
+        UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    for(size_t i = 0; i < subTypesSize; i++) {
+        hierarchy[i+1] = subTypes[i].nodeId;
+        UA_NodeId_init(&subTypes[i].nodeId);
+    }
+    for(size_t i = 0; i < interfacesSize; i++) {
+        hierarchy[i+1+subTypesSize] = interfaces[i].nodeId;
+        UA_NodeId_init(&interfaces[i].nodeId);
+    }
+
+    *typeHierarchy = hierarchy;
+    *typeHierarchySize = subTypesSize + interfacesSize + 1;
+
+    UA_assert(*typeHierarchySize < 1000);
+
+    UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
+    UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
     return UA_STATUSCODE_GOOD;
 }
 

+ 71 - 66
src/server/ua_services_nodemanagement.c

@@ -361,10 +361,8 @@ findChildByBrowsename(UA_Server *server, UA_Session *session,
 
     UA_BrowseResult br;
     UA_BrowseResult_init(&br);
-    struct BrowseOpts bo;
-    bo.maxReferences = 0;
-    bo.recursive = false;
-    Operation_Browse(server, session, &bo, &bd, &br);
+    UA_UInt32 maxrefs = 0;
+    Operation_Browse(server, session, &maxrefs, &bd, &br);
     if(br.statusCode != UA_STATUSCODE_GOOD)
         return br.statusCode;
 
@@ -527,10 +525,8 @@ copyAllChildren(UA_Server *server, UA_Session *session,
 
     UA_BrowseResult br;
     UA_BrowseResult_init(&br);
-    struct BrowseOpts bo;
-    bo.maxReferences = 0;
-    bo.recursive = false;
-    Operation_Browse(server, session, &bo, &bd, &br);
+    UA_UInt32 maxrefs = 0;
+    Operation_Browse(server, session, &maxrefs, &bd, &br);
     if(br.statusCode != UA_STATUSCODE_GOOD)
         return br.statusCode;
 
@@ -556,15 +552,15 @@ addTypeChildren(UA_Server *server, UA_Session *session,
                                                               &hierarchy, &hierarchySize);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
+    UA_assert(hierarchySize < 1000);
 
     /* Copy members of the type and supertypes (and instantiate them) */
     for(size_t i = 0; i < hierarchySize; ++i) {
         retval = copyAllChildren(server, session, &hierarchy[i], &node->nodeId);
         if(retval != UA_STATUSCODE_GOOD)
-            goto cleanup;
+            break;
     }
 
-cleanup:
     UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
     return retval;
 }
@@ -697,59 +693,75 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
         if(node->nodeClass == UA_NODECLASS_VARIABLE) {
             if(((const UA_VariableTypeNode*)type)->isAbstract) {
                 /* Get subtypes of the parent reference types */
-                UA_NodeId *parentTypeHierachy = NULL;
-                size_t parentTypeHierachySize = 0;
-                retval = getLocalRecursiveHierarchy(server, parentReferences, UA_PARENT_REFERENCES_COUNT,
-                                                    &subtypeId, 1, true, &parentTypeHierachy, &parentTypeHierachySize);
-                if(retval != UA_STATUSCODE_GOOD)
+                UA_NodeId *parentTypeHierarchy = NULL;
+                size_t parentTypeHierarchySize = 0;
+                retval |= referenceSubtypes(server, &parentReferences[0],
+                                            &parentTypeHierarchySize, &parentTypeHierarchy);
+                retval |= referenceSubtypes(server, &parentReferences[1],
+                                            &parentTypeHierarchySize, &parentTypeHierarchy);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize,
+                                    &UA_TYPES[UA_TYPES_NODEID]);
                     goto cleanup;
-                /* Abstract variable is allowed if parent is a children of a base data variable */
+                }
+
+                /* Abstract variable is allowed if parent is a children of a
+                 * base data variable. An abstract variable may be part of an
+                 * object type which again is below BaseObjectType */
                 const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
-                /* A variable may be of an object type which again is below BaseObjectType */
                 const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
                 if(!isNodeInTree(server->nsCtx, parentNodeId, &variableTypes,
-                                 parentTypeHierachy, parentTypeHierachySize) &&
+                                 parentTypeHierarchy, parentTypeHierarchySize) &&
                    !isNodeInTree(server->nsCtx, parentNodeId, &objectTypes,
-                                 parentTypeHierachy,parentTypeHierachySize)) {
-                    UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
+                                 parentTypeHierarchy, parentTypeHierarchySize)) {
                     UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session,
                                         "AddNodes: Type of variable node %.*s must "
                                         "be VariableType and not cannot be abstract",
                                         (int)nodeIdStr.length, nodeIdStr.data));
                     retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
-                    goto cleanup;
                 }
-                UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
+                UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize,
+                                &UA_TYPES[UA_TYPES_NODEID]);
+                if(retval != UA_STATUSCODE_GOOD)
+                    goto cleanup;
             }
         }
 
         if(node->nodeClass == UA_NODECLASS_OBJECT) {
             if(((const UA_ObjectTypeNode*)type)->isAbstract) {
                 /* Get subtypes of the parent reference types */
-                UA_NodeId *parentTypeHierachy = NULL;
-                size_t parentTypeHierachySize = 0;
-                retval = getLocalRecursiveHierarchy(server, parentReferences, UA_PARENT_REFERENCES_COUNT,
-                                                    &subtypeId, 1, true, &parentTypeHierachy, &parentTypeHierachySize);
-                if(retval != UA_STATUSCODE_GOOD)
+                UA_NodeId *parentTypeHierarchy = NULL;
+                size_t parentTypeHierarchySize = 0;
+                retval |= referenceSubtypes(server, &parentReferences[0],
+                                            &parentTypeHierarchySize, &parentTypeHierarchy);
+                retval |= referenceSubtypes(server, &parentReferences[1],
+                                            &parentTypeHierarchySize, &parentTypeHierarchy);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize,
+                                    &UA_TYPES[UA_TYPES_NODEID]);
                     goto cleanup;
+                }
+
                 /* Object node created of an abstract ObjectType. Only allowed
                  * if within BaseObjectType folder or if it's an event (subType of BaseEventType) */
                 const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
                 UA_Boolean isInBaseObjectType = isNodeInTree(server->nsCtx, parentNodeId, &objectTypes,
-                                                             parentTypeHierachy, parentTypeHierachySize);
+                                                             parentTypeHierarchy, parentTypeHierarchySize);
 
                 const UA_NodeId eventTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
                 UA_Boolean isInBaseEventType = isNodeInTree(server->nsCtx, &type->nodeId, &eventTypes, &hasSubtype, 1);
 
-                UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
                 if(!isInBaseObjectType && !(isInBaseEventType && UA_NodeId_isNull(parentNodeId))) {
                     UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session,
                                         "AddNodes: Type of object node %.*s must "
                                         "be ObjectType and not be abstract",
                                         (int)nodeIdStr.length, nodeIdStr.data));
                     retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
-                    goto cleanup;
                 }
+                UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize,
+                                &UA_TYPES[UA_TYPES_NODEID]);
+                if(retval != UA_STATUSCODE_GOOD)
+                    goto cleanup;
             }
         }
     }
@@ -1030,10 +1042,8 @@ recursiveCallConstructors(UA_Server *server, UA_Session *session,
 
     UA_BrowseResult br;
     UA_BrowseResult_init(&br);
-    struct BrowseOpts bo;
-    bo.maxReferences = 0;
-    bo.recursive = false;
-    Operation_Browse(server, session, &bo, &bd, &br);
+    UA_UInt32 maxrefs = 0;
+    Operation_Browse(server, session, &maxrefs, &bd, &br);
     if(br.statusCode != UA_STATUSCODE_GOOD)
         return br.statusCode;
 
@@ -1125,13 +1135,13 @@ recursiveCallConstructors(UA_Server *server, UA_Session *session,
 static void
 recursiveDeconstructNode(UA_Server *server, UA_Session *session,
                          size_t hierarchicalReferencesSize,
-                         UA_NodeId *hierarchicalReferences,
+                         UA_ExpandedNodeId *hierarchicalReferences,
                          const UA_Node *node);
 
 static void
 recursiveDeleteNode(UA_Server *server, UA_Session *session,
                     size_t hierarchicalReferencesSize,
-                    UA_NodeId *hierarchicalReferences,
+                    UA_ExpandedNodeId *hierarchicalReferences,
                     const UA_Node *node, UA_Boolean removeTargetRefs);
 
 /* Children, references, type-checking, constructors. */
@@ -1320,7 +1330,7 @@ removeIncomingReferences(UA_Server *server, UA_Session *session,
 /* A node can only be deleted if it has at most one incoming hierarchical
  * reference. If hierarchicalReferences is NULL, always remove. */
 static UA_Boolean
-multipleHierarchies(size_t hierarchicalRefsSize, UA_NodeId *hierarchicalRefs,
+multipleHierarchies(size_t hierarchicalRefsSize, UA_ExpandedNodeId *hierarchicalRefs,
                     const UA_Node *node) {
     if(!hierarchicalRefs)
         return false;
@@ -1333,7 +1343,7 @@ multipleHierarchies(size_t hierarchicalRefsSize, UA_NodeId *hierarchicalRefs,
 
         UA_Boolean hierarchical = false;
         for(size_t j = 0; j < hierarchicalRefsSize; j++) {
-            if(UA_NodeId_equal(&hierarchicalRefs[j],
+            if(UA_NodeId_equal(&hierarchicalRefs[j].nodeId,
                                &k->referenceTypeId)) {
                 hierarchical = true;
                 break;
@@ -1355,7 +1365,7 @@ multipleHierarchies(size_t hierarchicalRefsSize, UA_NodeId *hierarchicalRefs,
 static void
 recursiveDeconstructNode(UA_Server *server, UA_Session *session,
                          size_t hierarchicalRefsSize,
-                         UA_NodeId *hierarchicalRefs,
+                         UA_ExpandedNodeId *hierarchicalRefs,
                          const UA_Node *node) {
     /* Was the constructor called for the node? */
     if(!node->constructed)
@@ -1401,10 +1411,8 @@ recursiveDeconstructNode(UA_Server *server, UA_Session *session,
 
     UA_BrowseResult br;
     UA_BrowseResult_init(&br);
-    struct BrowseOpts bo;
-    bo.maxReferences = 0;
-    bo.recursive = false;
-    Operation_Browse(server, session, &bo, &bd, &br);
+    UA_UInt32 maxrefs = 0;
+    Operation_Browse(server, session, &maxrefs, &bd, &br);
     if(br.statusCode != UA_STATUSCODE_GOOD)
         return;
 
@@ -1427,7 +1435,7 @@ recursiveDeconstructNode(UA_Server *server, UA_Session *session,
 static void
 recursiveDeleteNode(UA_Server *server, UA_Session *session,
                     size_t hierarchicalRefsSize,
-                    UA_NodeId *hierarchicalRefs,
+                    UA_ExpandedNodeId *hierarchicalRefs,
                     const UA_Node *node, UA_Boolean removeTargetRefs) {
     /* Browse to get all children of the node */
     UA_BrowseDescription bd;
@@ -1439,10 +1447,8 @@ recursiveDeleteNode(UA_Server *server, UA_Session *session,
 
     UA_BrowseResult br;
     UA_BrowseResult_init(&br);
-    struct BrowseOpts bo;
-    bo.maxReferences = 0;
-    bo.recursive = false;
-    Operation_Browse(server, session, &bo, &bd, &br);
+    UA_UInt32 maxrefs = 0;
+    Operation_Browse(server, session, &maxrefs, &bd, &br);
     if(br.statusCode != UA_STATUSCODE_GOOD)
         return;
 
@@ -1474,10 +1480,11 @@ static void
 deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
                     const UA_DeleteNodesItem *item, UA_StatusCode *result) {
     /* Do not check access for server */
-    if(session != &server->adminSession && server->config.accessControl.allowDeleteNode &&
-       !server->config.accessControl.
-       allowDeleteNode(server, &server->config.accessControl, &session->sessionId,
-                       session->sessionHandle, item)) {
+    if(session != &server->adminSession &&
+       server->config.accessControl.allowDeleteNode &&
+       !server->config.accessControl.allowDeleteNode(server, &server->config.accessControl,
+                                                     &session->sessionId,
+                                                     session->sessionHandle, item)) {
         *result = UA_STATUSCODE_BADUSERACCESSDENIED;
         return;
     }
@@ -1505,22 +1512,20 @@ deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
      * hierarchical references are checked to see if a node can be deleted.
      * Getting the type hierarchy can fail in case of low RAM. In that case the
      * nodes are always deleted. */
-    UA_NodeId *hierarchicalRefs = NULL;
+    UA_ExpandedNodeId *hierarchicalRefs = NULL;
     size_t hierarchicalRefsSize = 0;
     UA_NodeId hr = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
-    getLocalRecursiveHierarchy(server, &hr, 1, &subtypeId, 1, true, &hierarchicalRefs, &hierarchicalRefsSize);
+    browseRecursive(server, 1, &hr, 1, &subtypeId, UA_BROWSEDIRECTION_FORWARD, true,
+                    &hierarchicalRefsSize, &hierarchicalRefs);
     if(!hierarchicalRefs) {
         UA_LOG_WARNING_SESSION(&server->config.logger, session,
                                "Delete Nodes: Cannot test for hierarchical "
                                "references. Deleting the node and all child nodes.");
     }
-
     recursiveDeconstructNode(server, session, hierarchicalRefsSize, hierarchicalRefs, node);
     recursiveDeleteNode(server, session, hierarchicalRefsSize, hierarchicalRefs, node,
                         item->deleteTargetReferences);
-
-    UA_Array_delete(hierarchicalRefs, hierarchicalRefsSize,
-                    &UA_TYPES[UA_TYPES_NODEID]);
+    UA_Array_delete(hierarchicalRefs, hierarchicalRefsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
     
     UA_Nodestore_releaseNode(server->nsCtx, node);
 }
@@ -1681,10 +1686,12 @@ static void
 Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
                           const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
     /* Do not check access for server */
-    if(session != &server->adminSession && server->config.accessControl.allowDeleteReference &&
-       !server->config.accessControl.
-       allowDeleteReference(server, &server->config.accessControl,
-                            &session->sessionId, session->sessionHandle, item)) {
+    if(session != &server->adminSession &&
+       server->config.accessControl.allowDeleteReference &&
+       !server->config.accessControl.allowDeleteReference(server,
+                                                          &server->config.accessControl,
+                                                          &session->sessionId,
+                                                          session->sessionHandle, item)) {
         *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
         return;
     }
@@ -1877,10 +1884,8 @@ UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId, UA_M
 
     UA_BrowseResult br;
     UA_BrowseResult_init(&br);
-    struct BrowseOpts bo;
-    bo.maxReferences = 0;
-    bo.recursive = false;
-    Operation_Browse(server, &server->adminSession, &bo, &bd, &br);
+    UA_UInt32 maxrefs = 0;
+    Operation_Browse(server, &server->adminSession, &maxrefs, &bd, &br);
 
     UA_StatusCode retval = br.statusCode;
     if(retval != UA_STATUSCODE_GOOD) {

File diff suppressed because it is too large
+ 444 - 404
src/server/ua_services_view.c


+ 6 - 15
src/server/ua_subscription_events.c

@@ -390,16 +390,10 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
     UA_Nodestore_releaseNode(server->nsCtx, originNode);
 
     /* Make sure the origin is in the ObjectsFolder (TODO: or in the ViewsFolder) */
-    UA_NodeId *parentTypeHierachy = NULL;
-    size_t parentTypeHierachySize = 0;
-    getLocalRecursiveHierarchy(server, parentReferences_events, 2, &subtypeId, 1,
-                               true, &parentTypeHierachy, &parentTypeHierachySize);
-    UA_Boolean isInObjectsFolder = isNodeInTree(server->nsCtx, &origin, &objectsFolderId,
-                                                parentTypeHierachy, parentTypeHierachySize);
-    if(!isInObjectsFolder) {
+    if(!isNodeInTree(server->nsCtx, &origin, &objectsFolderId,
+                     parentReferences_events, 2)) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "Node for event must be in ObjectsFolder!");
-        UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     }
 
@@ -408,17 +402,14 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Events: Could not set the standard event fields with StatusCode %s",
                        UA_StatusCode_name(retval));
-        UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
         return retval;
     }
 
     /* Get the parents */
-    UA_NodeId *parents = NULL;
+    UA_ExpandedNodeId *parents = NULL;
     size_t parentsSize = 0;
-    retval = getLocalRecursiveHierarchy(server, &origin, 1,
-                                        parentTypeHierachy, parentTypeHierachySize,
-                                        false, &parents, &parentsSize);
-    UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
+    retval = browseRecursive(server, 1, &origin, 2, parentReferences_events,
+                             UA_BROWSEDIRECTION_INVERSE, true, &parentsSize, &parents);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Events: Could not create the list of nodes listening on the "
@@ -429,7 +420,7 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
     /* Add the event to each node's monitored items */
     for(size_t i = 0; i < parentsSize; i++) {
         const UA_ObjectNode *node = (const UA_ObjectNode*)
-            UA_Nodestore_getNode(server->nsCtx, &parents[i]);
+            UA_Nodestore_getNode(server->nsCtx, &parents[i].nodeId);
         if(!node)
             continue;
         if(node->nodeClass != UA_NODECLASS_OBJECT) {