Browse Source

add object and variable type instantiation

Julius Pfrommer 9 years ago
parent
commit
5fcc80651d
3 changed files with 247 additions and 74 deletions
  1. 3 0
      src/server/ua_services.h
  2. 196 20
      src/server/ua_services_nodemanagement.c
  3. 48 54
      src/server/ua_services_view.c

+ 3 - 0
src/server/ua_services.h

@@ -148,6 +148,9 @@ UA_StatusCode Service_DeleteReferences_single(UA_Server *server, UA_Session *ses
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
                     UA_BrowseResponse *response);
 
+void Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
+                           const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result);
+
 /**
  * Used to request the next set of Browse or BrowseNext response information
  * that is too large to be sent in a single response. "Too large" in this

+ 196 - 20
src/server/ua_services_nodemanagement.c

@@ -84,23 +84,170 @@ void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *
 }
 
 static UA_StatusCode
-instantiateObject(const UA_NodeId *nodeId, const UA_AddNodesItem *item) {
-    /* /\* Get the parent node *\/ */
-    /* const UA_Node *parent = UA_NULL; */
-    /* if(!UA_NodeId_isNull(&item->parentNodeId.nodeId)) { */
-    /*     parent = UA_NodeStore_get(server->nodestore, &item->parentNodeId.nodeId); */
-    /*     if(!parent) { */
-    /*         result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID; */
-    /*         return; */
-    /*     } */
-    /*     if(parent->nodeClass == UA_NODECLASS_OBJECTTYPE) { */
-    /*         UA_NodeStore_release(parent); */
-    /*         result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID; */
-    /*         return; */
-    /*     } */
-    /* } */
-
-    /* /\* call the constructor *\/ */
+instantiateVariable(UA_Server *server, UA_Session *session,
+                    const UA_NodeId *nodeId, const UA_NodeId *typeId);
+static UA_StatusCode
+instantiateObject(UA_Server *server, UA_Session *session,
+                  const UA_NodeId *nodeId, const UA_NodeId *typeId);
+
+/* copy an existing variable under the given parent. then instantiate the
+   variable for all hastypedefinitions of the original version. */
+static UA_StatusCode
+copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
+                     const UA_NodeId *referenceType, const UA_NodeId *parent) {
+    const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
+    if(!node)
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    if(node->nodeClass != UA_NODECLASS_VARIABLE) {
+        UA_NodeStore_release((const UA_Node*)node);
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+    
+    // copy the variable attributes
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
+    UA_LocalizedText_copy(&node->displayName, &attr.displayName);
+    UA_LocalizedText_copy(&node->description, &attr.description);
+    attr.writeMask = node->writeMask;
+    attr.userWriteMask = node->userWriteMask;
+    // todo: handle data sources!!!!
+    UA_Variant_copy(&node->value.variant.value, &attr.value);
+    // datatype is taken from the value
+    // valuerank is taken from the value
+    // array dimensions are taken from the value
+    attr.accessLevel = node->accessLevel;
+    attr.userAccessLevel = node->userAccessLevel;
+    attr.minimumSamplingInterval = node->minimumSamplingInterval;
+    attr.historizing = node->historizing;
+
+    UA_AddNodesItem item;
+    UA_AddNodesItem_init(&item);
+    UA_NodeId_copy(parent, &item.parentNodeId.nodeId);
+    UA_NodeId_copy(referenceType, &item.referenceTypeId);
+    UA_QualifiedName_copy(&node->browseName, &item.browseName);
+    item.nodeClass = UA_NODECLASS_VARIABLE;
+    // don't add a typedefinition here.
+
+    // add the new variable
+    UA_AddNodesResult res;
+    UA_AddNodesResult_init(&res);
+    Service_AddNodes_single(server, session, &item, (UA_NodeAttributes*)&attr, &res);
+    UA_VariableAttributes_deleteMembers(&attr);
+    UA_AddNodesItem_deleteMembers(&item);
+
+    // now instantiate the variable for all hastypedefinition references
+    for(UA_Int32 i = 0; i < node->referencesSize; i++) {
+        UA_ReferenceNode *rn = &node->references[i];
+        if(rn->isInverse)
+            continue;
+        const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+        if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
+            continue;
+        instantiateVariable(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+    }
+
+    UA_AddNodesResult_deleteMembers(&res);
+    UA_NodeStore_release((const UA_Node*)node);
+    return UA_STATUSCODE_GOOD;
+}
+
+/* copy an existing variable under the given parent. then instantiate the
+   variable for all hastypedefinitions of the original version. */
+static UA_StatusCode
+copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
+                   const UA_NodeId *referenceType, const UA_NodeId *parent) {
+    const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
+    if(!node)
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    if(node->nodeClass != UA_NODECLASS_OBJECT) {
+        UA_NodeStore_release((const UA_Node*)node);
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+    // copy the variable attributes
+    UA_ObjectAttributes attr;
+    UA_ObjectAttributes_init(&attr);
+    UA_LocalizedText_copy(&node->displayName, &attr.displayName);
+    UA_LocalizedText_copy(&node->description, &attr.description);
+    attr.writeMask = node->writeMask;
+    attr.userWriteMask = node->userWriteMask;
+    attr.eventNotifier = node->eventNotifier;
+
+    UA_AddNodesItem item;
+    UA_AddNodesItem_init(&item);
+    UA_NodeId_copy(parent, &item.parentNodeId.nodeId);
+    UA_NodeId_copy(referenceType, &item.referenceTypeId);
+    UA_QualifiedName_copy(&node->browseName, &item.browseName);
+    item.nodeClass = UA_NODECLASS_OBJECT;
+    // don't add a typedefinition here.
+
+    // add the new object
+    UA_AddNodesResult res;
+    UA_AddNodesResult_init(&res);
+    Service_AddNodes_single(server, session, &item, (UA_NodeAttributes*)&attr, &res);
+    UA_ObjectAttributes_deleteMembers(&attr);
+    UA_AddNodesItem_deleteMembers(&item);
+
+    // now instantiate the object for all hastypedefinition references
+    for(UA_Int32 i = 0; i < node->referencesSize; i++) {
+        UA_ReferenceNode *rn = &node->references[i];
+        if(rn->isInverse)
+            continue;
+        const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+        if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
+            continue;
+        instantiateObject(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+    }
+
+    UA_AddNodesResult_deleteMembers(&res);
+    UA_NodeStore_release((const UA_Node*)node);
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+instantiateObject(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+    const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
+    if(!type)
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    if(type->nodeClass == UA_NODECLASS_OBJECTTYPE) {
+        UA_NodeStore_release((const UA_Node*)type);
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+
+    /* Add all the child nodes */
+    UA_BrowseDescription browseChildren;
+    UA_BrowseDescription_init(&browseChildren);
+    browseChildren.nodeId = *typeId;
+    browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
+    browseChildren.includeSubtypes = UA_TRUE;
+    browseChildren.browseDirection = UA_BROWSEDIRECTION_FORWARD;
+    browseChildren.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
+    browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS;
+
+    UA_BrowseResult browseResult;
+    UA_BrowseResult_init(&browseResult);
+    // todo: continuation points if there are too many results
+    Service_Browse_single(server, session, UA_NULL, &browseChildren, 100, &browseResult);
+
+    for(UA_Int32 i = 0; i < browseResult.referencesSize; i++) {
+        UA_ReferenceDescription *rd = &browseResult.references[i];
+        if(rd->nodeClass == UA_NODECLASS_METHOD) {
+            /* add a reference to the method in the objecttype */
+            UA_AddReferencesItem item;
+            UA_AddReferencesItem_init(&item);
+            item.sourceNodeId = *nodeId;
+            item.referenceTypeId = rd->referenceTypeId;
+            item.isForward = UA_TRUE;
+            item.targetNodeId = rd->nodeId;
+            item.targetNodeClass = UA_NODECLASS_METHOD;
+            Service_AddReferences_single(server, session, &item);
+        } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
+            copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+        else if(rd->nodeClass == UA_NODECLASS_OBJECT)
+            copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+    }
+    UA_NodeStore_release((const UA_Node*)type);
+
+    /* call the constructor */
     /* void *instanceHandle = */
     /*     ((const UA_ObjectTypeNode*)parent)->instanceManagement.constructor(result->addedNodeId); */
     /* UA_Server_editNode(server, session, &result->addedNodeId, */
@@ -112,7 +259,36 @@ instantiateObject(const UA_NodeId *nodeId, const UA_AddNodesItem *item) {
 }
 
 static UA_StatusCode
-instantiateVariable(const UA_NodeId *nodeId, const UA_AddNodesItem *item) {
+instantiateVariable(UA_Server *server, UA_Session *session,
+                    const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+    const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
+    if(!type)
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    if(type->nodeClass == UA_NODECLASS_VARIABLETYPE) {
+        UA_NodeStore_release((const UA_Node*)type);
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+
+    /* Add all the child nodes */
+    UA_BrowseDescription browseChildren;
+    UA_BrowseDescription_init(&browseChildren);
+    browseChildren.nodeId = *typeId;
+    browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
+    browseChildren.includeSubtypes = UA_TRUE;
+    browseChildren.browseDirection = UA_BROWSEDIRECTION_FORWARD;
+    browseChildren.nodeClassMask = UA_NODECLASS_VARIABLE;
+    browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS;
+
+    UA_BrowseResult browseResult;
+    UA_BrowseResult_init(&browseResult);
+    // todo: continuation points if there are too many results
+    Service_Browse_single(server, session, UA_NULL, &browseChildren, 100, &browseResult);
+
+    for(UA_Int32 i = 0; i < browseResult.referencesSize; i++) {
+        UA_ReferenceDescription *rd = &browseResult.references[i];
+        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+    }
+    UA_NodeStore_release((const UA_Node*)type);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -259,9 +435,9 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodes
         return;
     }
     if(item->nodeClass == UA_NODECLASS_OBJECT)
-        result->statusCode = instantiateObject(&result->addedNodeId, item);
+        result->statusCode = instantiateObject(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
     else if(item->nodeClass == UA_NODECLASS_VARIABLE)
-        result->statusCode = instantiateVariable(&result->addedNodeId, item);
+        result->statusCode = instantiateVariable(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
 }
 
 static void Service_AddNodes_single_unparsed(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,

+ 48 - 54
src/server/ua_services_view.c

@@ -4,12 +4,11 @@
 #include "ua_nodestore.h"
 #include "ua_util.h"
 
-static UA_StatusCode fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref,
-                                  UA_UInt32 mask, UA_ReferenceDescription *descr)
-{
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+static UA_StatusCode
+fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref,
+                         UA_UInt32 mask, UA_ReferenceDescription *descr) {
     UA_ReferenceDescription_init(descr);
-    retval |= UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
+    UA_StatusCode retval = UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
     //TODO: ExpandedNodeId is mocked up
     descr->nodeId.serverIndex = 0;
     descr->nodeId.namespaceUri.length = -1;
@@ -43,10 +42,9 @@ static UA_StatusCode fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_Refe
 
 /* Tests if the node is relevant to the browse request and shall be returned. If
    so, it is retrieved from the Nodestore. If not, null is returned. */
-static const UA_Node *relevant_node(UA_Server *server, UA_NodeStore *ns, const UA_BrowseDescription *descr,
-                                    UA_Boolean return_all, UA_ReferenceNode *reference,
-                                    UA_NodeId *relevant, size_t relevant_count, UA_Boolean *isExternal)
-{
+static const UA_Node *
+isRelevantNode(UA_Server *server, const UA_BrowseDescription *descr, UA_Boolean return_all,
+               UA_ReferenceNode *reference, UA_NodeId *relevant, size_t relevant_count, UA_Boolean *isExternal) {
     if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
         return UA_NULL;
     else if(reference->isInverse == UA_FALSE && descr->browseDirection == UA_BROWSEDIRECTION_INVERSE)
@@ -72,8 +70,8 @@ is_relevant: ;
 			break;
 		}
 	}
-	if(*isExternal == UA_FALSE){
-		node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
+	if(*isExternal == UA_FALSE) {
+		node = UA_NodeStore_get(server->nodestore, &reference->targetId.nodeId);
 	} else {
 		/*	prepare a read request in the external nodestore	*/
 		UA_ExternalNodeStore *ens = &server->externalNamespaces[nsIndex].externalNodeStore;
@@ -102,24 +100,18 @@ is_relevant: ;
 		/*	create and fill a dummy nodeStructure	*/
 		UA_Node *tempNode = (UA_Node*) UA_ObjectNode_new();
 		UA_NodeId_copy(&(reference->targetId.nodeId), &(tempNode->nodeId));
-		if(readNodesResults[0].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[0].status == UA_STATUSCODE_GOOD)
 			UA_NodeClass_copy((UA_NodeClass*)readNodesResults[0].value.data, &(tempNode->nodeClass));
-		}
-		if(readNodesResults[1].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[1].status == UA_STATUSCODE_GOOD)
 			UA_QualifiedName_copy((UA_QualifiedName*)readNodesResults[1].value.data, &(tempNode->browseName));
-		}
-		if(readNodesResults[2].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[2].status == UA_STATUSCODE_GOOD)
 			UA_LocalizedText_copy((UA_LocalizedText*)readNodesResults[2].value.data, &(tempNode->displayName));
-		}
-		if(readNodesResults[3].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[3].status == UA_STATUSCODE_GOOD)
 			UA_LocalizedText_copy((UA_LocalizedText*)readNodesResults[3].value.data, &(tempNode->description));
-		}
-		if(readNodesResults[4].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[4].status == UA_STATUSCODE_GOOD)
 			UA_UInt32_copy((UA_UInt32*)readNodesResults[4].value.data, &(tempNode->writeMask));
-		}
-		if(readNodesResults[5].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[5].status == UA_STATUSCODE_GOOD)
 			UA_UInt32_copy((UA_UInt32*)readNodesResults[5].value.data, &(tempNode->userWriteMask));
-		}
 		UA_Array_delete(readValueIds, &UA_TYPES[UA_TYPES_READVALUEID], 6);
 		UA_Array_delete(indices, &UA_TYPES[UA_TYPES_UINT32], 6);
 		UA_Array_delete(readNodesResults, &UA_TYPES[UA_TYPES_DATAVALUE], 6);
@@ -127,7 +119,7 @@ is_relevant: ;
 		node = tempNode;
 	}
 #else
-    const UA_Node *node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &reference->targetId.nodeId);
 #endif
     if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
 #ifdef UA_EXTERNAL_NAMESPACES
@@ -147,8 +139,8 @@ is_relevant: ;
  * the array and increase the size. Since the hierarchy is not cyclic, we can safely progress in the
  * array to process the newly found referencetype nodeids (emulated recursion).
  */
-static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes,
-                                  size_t *reftypes_count) {
+static UA_StatusCode
+findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size_t *reftypes_count) {
     const UA_Node *node = UA_NodeStore_get(ns, root);
     if(!node)
         return UA_STATUSCODE_BADNOMATCH;
@@ -209,7 +201,7 @@ static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_No
     return UA_STATUSCODE_GOOD;
 }
 
-static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session){
+static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session) {
     session->availableContinuationPoints++;
     UA_ByteString_deleteMembers(&cp->identifier);
     UA_BrowseDescription_deleteMembers(&cp->browseDescription);
@@ -221,14 +213,15 @@ static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session){
  * Results for a single browsedescription. This is the inner loop for both Browse and BrowseNext
  * @param session Session to save continuationpoints
  * @param ns The nodstore where the to-be-browsed node can be found
- * @param cp If cp points to a continuationpoint, we continue from there.
+ * @param cp If cp is not null, we continue from here
  *           If cp is null, we can add a new continuation point if possible and necessary.
  * @param descr If no cp is set, we take the browsedescription from there
  * @param maxrefs The maximum number of references the client has requested
  * @param result The entry in the request
  */
-static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, struct ContinuationPointEntry *cp,
-                   const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
+void
+Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
+                      const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
     UA_UInt32 continuationIndex = 0;
     size_t referencesCount = 0;
     UA_Int32 referencesIndex = 0;
@@ -254,15 +247,17 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
     UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
     if(!all_refs) {
         if(descr->includeSubtypes) {
-            result->statusCode = findsubtypes(ns, &descr->referenceTypeId, &relevant_refs, &relevant_refs_size);
+            result->statusCode = findSubTypes(server->nodestore, &descr->referenceTypeId,
+                                              &relevant_refs, &relevant_refs_size);
             if(result->statusCode != UA_STATUSCODE_GOOD)
                 return;
         } else {
-            const UA_Node *rootRef = UA_NodeStore_get(ns, &descr->referenceTypeId);
+            const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &descr->referenceTypeId);
             if(!rootRef) {
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 return;
-            } else if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
+            }
+            if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
                 UA_NodeStore_release(rootRef);
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 return;
@@ -274,7 +269,7 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
     }
 
     /* get the node */
-    const UA_Node *node = UA_NodeStore_get(ns, &descr->nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &descr->nodeId);
     if(!node) {
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(!all_refs && descr->includeSubtypes)
@@ -306,34 +301,32 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
     UA_Boolean isExternal = UA_FALSE;
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
     	isExternal = UA_FALSE;
-    	const UA_Node *current = relevant_node(server, ns, descr, all_refs, &node->references[referencesIndex],
-                                               relevant_refs, relevant_refs_size, &isExternal);
+    	const UA_Node *current = isRelevantNode(server, descr, all_refs, &node->references[referencesIndex],
+                                                relevant_refs, relevant_refs_size, &isExternal);
         if(!current)
             continue;
         if(skipped < continuationIndex) {
 #ifdef UA_EXTERNAL_NAMESPACES
-        	if(isExternal == UA_TRUE){
+        	if(isExternal == UA_TRUE)
         		/*	relevant_node returns a node malloced with UA_ObjectNode_new if it is external (there is no UA_Node_new function)	*/
         		UA_ObjectNode_delete((UA_ObjectNode*)current);
-        	} else {
+        	else
         		UA_NodeStore_release(current);
-        	}
 #else
         	UA_NodeStore_release(current);
 #endif
             skipped++;
             continue;
         }
-        UA_StatusCode retval = fillrefdescr(ns, current, &node->references[referencesIndex], descr->resultMask,
-                                            &result->references[referencesCount]);
+        UA_StatusCode retval = fillReferenceDescription(server->nodestore, current, &node->references[referencesIndex],
+                                                        descr->resultMask, &result->references[referencesCount]);
 #ifdef UA_EXTERNAL_NAMESPACES
-        if(isExternal == UA_TRUE){
+        if(isExternal == UA_TRUE)
         	UA_ObjectNode_delete((UA_ObjectNode*)current);
-        } else {
+        else
         	UA_NodeStore_release(current);
-        }
 #else
-        	UA_NodeStore_release(current);
+        UA_NodeStore_release(current);
 #endif
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], referencesCount);
@@ -370,7 +363,8 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
         }
     } else if(maxrefs != 0 && referencesCount >= maxrefs) {
         /* create a cp */
-        if(session->availableContinuationPoints <= 0 || !(cp = UA_malloc(sizeof(struct ContinuationPointEntry)))) {
+        if(session->availableContinuationPoints <= 0 ||
+           !(cp = UA_malloc(sizeof(struct ContinuationPointEntry)))) {
             result->statusCode = UA_STATUSCODE_BADNOCONTINUATIONPOINTS;
             return;
         }
@@ -440,8 +434,8 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
-            browse(server, session, server->nodestore, UA_NULL, &request->nodesToBrowse[i],
-                   request->requestedMaxReferencesPerNode, &response->results[i]);
+            Service_Browse_single(server, session, UA_NULL, &request->nodesToBrowse[i],
+                                  request->requestedMaxReferencesPerNode, &response->results[i]);
     }
 }
 
@@ -464,7 +458,7 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
            struct ContinuationPointEntry *cp;
            LIST_FOREACH(cp, &session->continuationPoints, pointers) {
                if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
-                   browse(server, session, server->nodestore, cp, UA_NULL, 0, &response->results[i]);
+                   Service_Browse_single(server, session, cp, UA_NULL, 0, &response->results[i]);
                    break;
                }
            }
@@ -500,8 +494,7 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
 static UA_StatusCode
 walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
                UA_Int32 pathindex, UA_BrowsePathTarget **targets, UA_Int32 *targets_size,
-               UA_Int32 *target_count)
-{
+               UA_Int32 *target_count) {
     const UA_RelativePathElement *elem = &path->elements[pathindex];
     if(elem->targetName.name.length == -1)
         return UA_STATUSCODE_BADBROWSENAMEINVALID;
@@ -515,7 +508,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
     else if(!elem->includeSubtypes)
         reftypes = (UA_NodeId*)(uintptr_t)&elem->referenceTypeId; // ptr magic due to const cast
     else {
-        retval = findsubtypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
+        retval = findSubTypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
     }
@@ -577,8 +570,9 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
     return retval;
 }
 
-static void translateBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
-                                UA_BrowsePathResult *result) {
+static void
+translateBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
+                    UA_BrowsePathResult *result) {
     if(path->relativePath.elementsSize <= 0) {
         result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
         return;