Browse Source

cleanup address space

Julius Pfrommer 9 years ago
parent
commit
eeb30de178

+ 0 - 44
include/ua_server.h

@@ -128,54 +128,11 @@ UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_NodeI
  *
  * @param server The server object
  * @param nodeId ID of the node to be deleted
-
  * @return Return UA_STATUSCODE_GOOD if the node was deleted or an appropriate errorcode if the node was not found
  *         or cannot be deleted.
  */
 UA_StatusCode UA_EXPORT UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId);
 
-#define UA_SERVER_DELETENODEALIAS_DECL(TYPE) \
-UA_StatusCode UA_EXPORT UA_Server_delete##TYPE##Node(UA_Server *server, UA_NodeId nodeId);
-
-UA_SERVER_DELETENODEALIAS_DECL(Object)
-UA_SERVER_DELETENODEALIAS_DECL(Variable)
-UA_SERVER_DELETENODEALIAS_DECL(ReferenceType)
-UA_SERVER_DELETENODEALIAS_DECL(View)
-UA_SERVER_DELETENODEALIAS_DECL(VariableType)
-UA_SERVER_DELETENODEALIAS_DECL(DataType)
-
-#ifdef ENABLE_METHODCALLS
-UA_SERVER_DELETENODEALIAS_DECL(Method)
-#endif
-
-/** Deletes a copied instance of a node by deallocating it and all its attributes. This assumes that the node was
- * priorly copied using getNodeCopy. To delete nodes that are located in the nodestore, use UA_Server_deleteNode()
- * instead.
- *
- * @param server The server object
- * @param node   A copy of any node-type struct created with getNodeCopy; must *not* be managed by the nodestore.
- * 
- * @return Return UA_STATUSCODE_GOOD if the node was deleted or an appropriate errorcode if the node was not found
- *         or cannot be deleted.
- */
-UA_StatusCode UA_EXPORT 
-UA_Server_deleteNodeCopy(UA_Server *server, void **node);
-
-/** Creates a deep copy of a node located in the nodestore and returns it to the userspace. Note that any manipulation
- * of this copied node is not reflected by the server, but otherwise not accessible attributes of the node's struct
- * can be examined in bulk. node->nodeClass can be used to cast the node to a specific node type. Use 
- * UA_Server_deleteNodeCopy() to deallocate this node.
- *
- * @param server The server object
- * @param nodeId ID of the node copy to be copied
- * @param copyInto Pointer to a NULL pointer that will hold the copy of the node on a successfull return.
- * 
- * @return Return UA_STATUSCODE_GOOD if the node was copied or an appropriate errorcode if the node was not found
- *         or cannot be copied.
- */
-UA_StatusCode UA_EXPORT 
-UA_Server_getNodeCopy(UA_Server *server, UA_NodeId nodeId, void **copyInto);
-
 /** A new variable Node with a value passed in variant.
  *
  * @param server The server object
@@ -189,7 +146,6 @@ UA_Server_getNodeCopy(UA_Server *server, UA_NodeId nodeId, void **copyInto);
  * @param referenceTypeId Reference type used by the parent to reference this node
  * @param value         A variant containing the value to be assigned to this node.
  * @param createdNodeId Pointer to a NULL pointer that will hold the copy of the nodeId on a successfull return.
- * 
  * @return Return UA_STATUSCODE_GOOD if the node was created or an appropriate error code if not.
  */
 UA_StatusCode UA_EXPORT

+ 95 - 0
src/server/ua_nodes.c

@@ -40,6 +40,101 @@ static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 	return retval;
 }
 
+void UA_Node_deleteAnyNodeClass(UA_Node *node) {
+    switch(node->nodeClass) {
+    UA_NODECLASS_OBJECT:
+        UA_ObjectNode_delete((UA_ObjectNode*)node);
+        break;
+    UA_NODECLASS_VARIABLE:
+        UA_VariableNode_delete((UA_VariableNode*)node);
+        break;
+    UA_NODECLASS_METHOD:
+        UA_MethodNode_delete((UA_MethodNode*)node);
+        break;
+    UA_NODECLASS_OBJECTTYPE:
+        UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
+        break;
+    UA_NODECLASS_VARIABLETYPE:
+        UA_VariableTypeNode_delete((UA_VariableTypeNode*)node);
+        break;
+    UA_NODECLASS_REFERENCETYPE:
+        UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
+        break;
+    UA_NODECLASS_DATATYPE:
+        UA_DataTypeNode_delete((UA_DataTypeNode*)node);
+        break;
+    UA_NODECLASS_VIEW:
+        UA_ViewNode_delete((UA_ViewNode*)node);
+        break;
+    default:
+        break;
+    }
+}
+
+typedef const UA_Node *(*UA_CopyNodeFunction)(const UA_Node *src, UA_Node *dst);
+typedef const UA_Node *(*UA_NewNodeFunction)(void);
+typedef void (*UA_DeleteNodeFunction)(UA_Node *p);
+
+UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node) {
+    UA_NewNodeFunction newNode;
+    UA_CopyNodeFunction copyNode;
+    UA_DeleteNodeFunction deleteNode;
+
+    switch(node->nodeClass) {
+    UA_NODECLASS_OBJECT:
+        newNode = (UA_NewNodeFunction)UA_ObjectNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ObjectNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ObjectNode_delete;
+        break;
+    UA_NODECLASS_VARIABLE:
+        newNode = (UA_NewNodeFunction)UA_VariableNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_VariableNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_VariableNode_delete;
+        break;
+    UA_NODECLASS_METHOD:
+        newNode = (UA_NewNodeFunction)UA_MethodNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_MethodNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_MethodNode_delete;
+        break;
+    UA_NODECLASS_OBJECTTYPE:
+        newNode = (UA_NewNodeFunction)UA_ObjectTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ObjectTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ObjectTypeNode_delete;
+        break;
+    UA_NODECLASS_VARIABLETYPE:
+        newNode = (UA_NewNodeFunction)UA_VariableTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_VariableTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_VariableTypeNode_delete;
+        break;
+    UA_NODECLASS_REFERENCETYPE:
+        newNode = (UA_NewNodeFunction)UA_ReferenceTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ReferenceTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ReferenceTypeNode_delete;
+        break;
+    UA_NODECLASS_DATATYPE:
+        newNode = (UA_NewNodeFunction)UA_DataTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_DataTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_DataTypeNode_delete;
+        break;
+    UA_NODECLASS_VIEW:
+        newNode = (UA_NewNodeFunction)UA_ViewNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ViewNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ViewNode_delete;
+        break;
+    default:
+        return UA_NULL;
+    }
+
+    UA_Node *copy = newNode();
+    if(!copy)
+        return UA_NULL;
+    if(copyNode(node, copy) != UA_STATUSCODE_GOOD) {
+        deleteNode(copy);
+        return UA_NULL;
+    }
+    return copy;
+}
+
 /* UA_ObjectNode */
 void UA_ObjectNode_init(UA_ObjectNode *p) {
 	UA_Node_init((UA_Node*)p);

+ 3 - 0
src/server/ua_nodes.h

@@ -20,6 +20,9 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
 } UA_Node;
 
+void UA_Node_deleteAnyNodeClass(UA_Node *node);
+UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node);
+
 /**************/
 /* ObjectNode */
 /**************/

+ 140 - 465
src/server/ua_server_addressspace.c

@@ -2,13 +2,7 @@
 #include "ua_services.h"
 #include "ua_server_internal.h"
 
-#define UA_SERVER_DELETENODEALIAS(TYPE) \
-UA_StatusCode UA_Server_delete##TYPE##Node(UA_Server *server, UA_NodeId nodeId) { \
-  return UA_Server_deleteNode(server, nodeId); \
-}
-
-UA_StatusCode 
-UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
+UA_StatusCode UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
   union nodeUnion {
     const UA_Node *delNodeConst;
     UA_Node *delNode;
@@ -29,131 +23,28 @@ UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
   return UA_STATUSCODE_GOOD;
 }
 
-UA_SERVER_DELETENODEALIAS(Object)
-UA_SERVER_DELETENODEALIAS(Variable)
-UA_SERVER_DELETENODEALIAS(ReferenceType)
-UA_SERVER_DELETENODEALIAS(View)
-UA_SERVER_DELETENODEALIAS(VariableType)
-UA_SERVER_DELETENODEALIAS(DataType)
-#ifdef ENABLE_METHODCALLS
-UA_SERVER_DELETENODEALIAS(Method)
-#endif
-
-UA_StatusCode UA_Server_getNodeCopy(UA_Server *server, UA_NodeId nodeId, void **copyInto) {
-  const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
-  UA_Node **copy = (UA_Node **) copyInto;
-  
-  UA_StatusCode retval = UA_STATUSCODE_GOOD;
-  
-  if (!node)
-    return UA_STATUSCODE_BADNODEIDINVALID;
-  
-  switch(node->nodeClass) {
-    case UA_NODECLASS_DATATYPE:
-      *copy = (UA_Node *) UA_VariableNode_new();
-      retval |= UA_DataTypeNode_copy((const UA_DataTypeNode *) node, (UA_DataTypeNode *) *copy);
-      break;
-    case UA_NODECLASS_METHOD:
-      *copy =  (UA_Node *) UA_MethodNode_new();
-      retval |= UA_MethodNode_copy((const UA_MethodNode *) node, (UA_MethodNode *) *copy);
-      break;      
-    case UA_NODECLASS_OBJECT:
-      *copy =  (UA_Node *) UA_ObjectNode_new();
-      retval |= UA_ObjectNode_copy((const UA_ObjectNode *) node, (UA_ObjectNode *) *copy);
-      break;      
-    case UA_NODECLASS_OBJECTTYPE:
-      *copy =  (UA_Node *) UA_ObjectTypeNode_new();
-      retval |= UA_ObjectTypeNode_copy((const UA_ObjectTypeNode *) node, (UA_ObjectTypeNode *) *copy);
-      break;      
-    case UA_NODECLASS_REFERENCETYPE:
-      *copy =  (UA_Node *) UA_ReferenceTypeNode_new();
-      retval |= UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode *) node, (UA_ReferenceTypeNode *) *copy);
-      break;      
-    case UA_NODECLASS_VARIABLE:
-      *copy =  (UA_Node *) UA_VariableNode_new();
-      retval |= UA_VariableNode_copy((const UA_VariableNode *) node, (UA_VariableNode *) *copy);
-      break;      
-    case UA_NODECLASS_VARIABLETYPE:
-      *copy =  (UA_Node *) UA_VariableTypeNode_new();
-      retval |= UA_VariableTypeNode_copy((const UA_VariableTypeNode *) node, (UA_VariableTypeNode *) *copy);
-      break;      
-    case UA_NODECLASS_VIEW:
-      *copy =  (UA_Node *) UA_ViewNode_new();
-      retval |= UA_ViewNode_copy((const UA_ViewNode *) node, (UA_ViewNode *) *copy);
-      break;      
-    default:
-      break;
-  }
-  
-  UA_NodeStore_release(node);
-  
-  return retval;
-} 
-
-UA_StatusCode UA_Server_deleteNodeCopy(UA_Server *server, void **nodeptr) {
-  UA_StatusCode retval = UA_STATUSCODE_GOOD;
-  UA_Node **node = (UA_Node **) nodeptr;
-  
-  if (!(*node))
-    return UA_STATUSCODE_BADNODEIDINVALID;
-  
-  switch((*node)->nodeClass) {
-    case UA_NODECLASS_DATATYPE:
-      UA_DataTypeNode_delete((UA_DataTypeNode *) *node);
-      break;
-    case UA_NODECLASS_METHOD:
-      UA_MethodNode_delete((UA_MethodNode *) *node);
-      break;      
-    case UA_NODECLASS_OBJECT:
-      UA_ObjectNode_delete((UA_ObjectNode *) *node);
-      break;      
-    case UA_NODECLASS_OBJECTTYPE:
-      UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) *node);
-      break;      
-    case UA_NODECLASS_REFERENCETYPE:
-      UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) *node);
-      break;      
-    case UA_NODECLASS_VARIABLE:
-      UA_VariableNode_delete((UA_VariableNode *) *node);
-      break;      
-    case UA_NODECLASS_VARIABLETYPE:
-      UA_VariableTypeNode_delete((UA_VariableTypeNode *) *node);
-      break;      
-    case UA_NODECLASS_VIEW:
-      UA_ViewNode_delete((UA_ViewNode *) *node);
-      break;      
-    default:
-      break;
-  }
-  
-  return retval;
-} 
-
-UA_StatusCode 
-UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, UA_NodeIteratorCallback callback, void *handle) {
-  UA_StatusCode retval = UA_STATUSCODE_GOOD;
-  const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
-  if (!parent)
-    return UA_STATUSCODE_BADNODEIDINVALID;
-  
-  for(int i=0; i<parent->referencesSize; i++) {
-    UA_ReferenceNode *ref = &parent->references[i];
-    retval |= callback(ref->targetId.nodeId, ref->isInverse, ref->referenceTypeId, handle);
-  }
-  
-  UA_NodeStore_release(parent);
-  return retval;
+UA_StatusCode UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
+                                             UA_NodeIteratorCallback callback, void *handle) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
+    if(!parent)
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    
+    for(int i=0; i<parent->referencesSize; i++) {
+        UA_ReferenceNode *ref = &parent->references[i];
+        retval |= callback(ref->targetId.nodeId, ref->isInverse, ref->referenceTypeId, handle);
+    }
+    
+    UA_NodeStore_release(parent);
+    return retval;
 }
 
 UA_StatusCode
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
+                          const UA_LocalizedText displayName, const UA_LocalizedText description,
+                          const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-                          UA_Variant *value,
-
-                          UA_NodeId *createdNodeId) {
+                          UA_Variant *value, UA_NodeId *createdNodeId) {
     UA_VariableNode *node = UA_VariableNode_new();
     UA_StatusCode retval;
     node->value.variant = *value; // copy content
@@ -186,13 +77,10 @@ UA_Server_addVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_Qu
 
 UA_StatusCode
 UA_Server_addObjectNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
+                        const UA_LocalizedText displayName, const UA_LocalizedText description,
+                        const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-                        const UA_ExpandedNodeId typeDefinition,
-
-                        UA_NodeId *createdNodeId){
+                        const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId){
     UA_ObjectNode *node = UA_ObjectNode_new();
     UA_StatusCode retval;
     
@@ -222,14 +110,10 @@ UA_Server_addObjectNode(UA_Server *server, const UA_NodeId nodeId, const UA_Qual
 
 UA_StatusCode
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                                    const UA_LocalizedText displayName, const UA_LocalizedText description,  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-                                    const UA_NodeId parentNodeId,
-                                    const UA_NodeId referenceTypeId,
-
-                                    const UA_DataSource dataSource,
-
-                                    UA_NodeId *createdNodeId) {
+                                    const UA_LocalizedText displayName, const UA_LocalizedText description,
+                                    const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+                                    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                                    const UA_DataSource dataSource, UA_NodeId *createdNodeId) {
     UA_VariableNode *node = UA_VariableNode_new();
     UA_StatusCode retval;
     
@@ -260,16 +144,11 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId nodeId, c
                                     
 UA_StatusCode
 UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-        const UA_NodeId parentNodeId,
-        const UA_NodeId referenceTypeId,
-
-        UA_Variant *value,
-        const UA_Int32 valueRank,
-        const UA_Boolean isAbstract,
-
-        UA_NodeId *createdNodeId) {
+                              const UA_LocalizedText displayName, const UA_LocalizedText description,
+                              const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                              UA_Variant *value, const UA_Int32 valueRank, const UA_Boolean isAbstract,
+                              UA_NodeId *createdNodeId) {
     UA_VariableTypeNode *node = UA_VariableTypeNode_new();
     UA_StatusCode retval;
     node->value.variant = *value; // copy content
@@ -303,15 +182,11 @@ UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId nodeId, const U
 
 UA_StatusCode
 UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-        const UA_NodeId parentNodeId,
-        const UA_NodeId referenceTypeId,
-
-        const UA_ExpandedNodeId typeDefinition,
-        const UA_Boolean isAbstract,
-
-        UA_NodeId *createdNodeId) {
+                          const UA_LocalizedText displayName, const UA_LocalizedText description,
+                          const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                          const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
+                          UA_NodeId *createdNodeId) {
   UA_DataTypeNode *node = UA_DataTypeNode_new();
   UA_StatusCode retval;
   
@@ -343,14 +218,10 @@ UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_Qu
 
 UA_StatusCode
 UA_Server_addViewNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-        const UA_NodeId parentNodeId,
-        const UA_NodeId referenceTypeId,
-
-        const UA_ExpandedNodeId typeDefinition,
-
-        UA_NodeId *createdNodeId) {
+                      const UA_LocalizedText displayName, const UA_LocalizedText description,
+                      const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                      const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId) {
   UA_ViewNode *node = UA_ViewNode_new();
   UA_StatusCode retval;
   
@@ -382,14 +253,11 @@ UA_Server_addViewNode(UA_Server *server, const UA_NodeId nodeId, const UA_Qualif
 }
 
 UA_StatusCode UA_Server_addReferenceTypeNode (UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-        const UA_ExpandedNodeId typeDefinition,
-        const UA_LocalizedText inverseName,
-
-        UA_NodeId *createdNodeId ){
+                                              const UA_LocalizedText displayName, const UA_LocalizedText description,
+                                              const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+                                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                                              const UA_ExpandedNodeId typeDefinition, const UA_LocalizedText inverseName,
+                                              UA_NodeId *createdNodeId) {
   UA_ReferenceTypeNode *node = UA_ReferenceTypeNode_new();
   UA_StatusCode retval;
   
@@ -419,14 +287,11 @@ UA_StatusCode UA_Server_addReferenceTypeNode (UA_Server *server, const UA_NodeId
 }
 
 UA_StatusCode UA_Server_addObjectTypeNode (UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-        const UA_ExpandedNodeId typeDefinition,
-        const UA_Boolean isAbstract,
-
-        UA_NodeId *createdNodeId ){
+                                           const UA_LocalizedText displayName, const UA_LocalizedText description,
+                                           const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+                                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                                           const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
+                                           UA_NodeId *createdNodeId) {
   UA_ObjectTypeNode *node = UA_ObjectTypeNode_new();
   UA_StatusCode retval;
   
@@ -607,59 +472,54 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
 }
 
 UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
-  UA_Node *node = UA_NULL;
-  UA_StatusCode retval = UA_Server_getNodeCopy(server, item->sourceNodeId, (void *) &node);
-  if (!node)
-    return retval;
-  
-  // Copy all that do not target the targetNode in a new array
-  UA_ReferenceNode *newRefs = (UA_ReferenceNode*) UA_malloc(sizeof(UA_ReferenceNode) * node->referencesSize);
-  UA_UInt32 newRefCount = 0;
-  for(int refn = 0; refn < node->referencesSize; refn++) {
-    // Completely different target node:
-    if (!UA_NodeId_equal(&item->targetNodeId.nodeId, &node->references[refn].targetId.nodeId)) {
-      UA_ReferenceNode_copy(&node->references[refn], &newRefs[newRefCount]);
-      newRefCount++;
+    const UA_Node *orig;
+ repeat_deleteref_oneway:
+    orig = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
+    if(!orig)
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+
+#ifndef UA_MULTITHREADING
+    /* We cheat if multithreading is not enabled and treat the node as mutable. */
+    UA_Node *editable = (UA_Node*)(uintptr_t)orig;
+#else
+    UA_Node *editable = UA_Node_copyAnyNodeClass(orig);
+    UA_Boolean edited = UA_FALSE;;
+#endif
+
+    for(UA_Int32 i = editable->referencesSize - 1; i >= 0; i--) {
+        if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &editable->references[i].targetId.nodeId))
+            continue;
+        if(!UA_NodeId_equal(&item->referenceTypeId, &editable->references[i].referenceTypeId))
+            continue;
+        if(item->isForward == editable->references[i].isInverse)
+            continue;
+        /* move the last entry to override the current position */
+        UA_ReferenceNode_deleteMembers(&editable->references[i]);
+        editable->references[i] = editable->references[editable->referencesSize-1];
+        editable->referencesSize--;
+
+#ifdef UA_MULTITHREADING
+        edited = UA_TRUE;
+#endif
     }
-    else {
-      // Correct target node, wrong referenceType
-      if (!UA_NodeId_equal(&item->referenceTypeId, &node->references[refn].referenceTypeId)) {
-        UA_ReferenceNode_copy(&node->references[refn], &newRefs[newRefCount]);
-        newRefCount++;
-      }
-      else {
-        // Correct target, correct referenceType, wrong direction
-        // FIXME: Check semantics of deleteBidirectional: does it mean we delete any forward or inverse refs 
-        //        in this node (assumed here) OR does it mean we remove Invers refs from target node??
-        if (item->deleteBidirectional == UA_FALSE && (item->isForward != node->references[refn].isInverse)) {
-          UA_ReferenceNode_copy(&node->references[refn], &newRefs[newRefCount]);
-          newRefCount++;
-        }
-        // else... everything matches, don't copy this node into the new reference array. 
-      }
+
+    /* we removed the last reference */
+    if(editable->referencesSize <= 0 && editable->references)
+        UA_free(editable->references);
+    
+#ifdef UA_MULTITHREADING
+    if(!edited) {
+        UA_Node_deleteAnyNodeClass(edited);
+    } else if(UA_NodeStore_replace(server->nodestore, orig, editable, UA_NULL) != UA_STATUSCODE_GOOD) {
+        /* the node was changed by another thread. repeat. */
+        UA_Node_deleteAnyNodeClass(edited);
+        UA_NodeStore_release(orig);
+        goto repeat_deleteref_oneway;
     }
-  }
-  
-  // Reallocate
-  UA_ReferenceNode *tmp = UA_realloc(newRefs, sizeof(UA_ReferenceNode) * newRefCount);
-  if (!tmp) {
-    if (newRefCount > 0) 
-      UA_free(newRefs); //realloc with zero size is equal to free!
-    UA_Server_deleteNodeCopy(server, (void *) &node);
-    return UA_STATUSCODE_BADOUTOFMEMORY;
-  }
-  newRefs = tmp;
-  
-  // Swap old references in node for new ones, then free old array
-  tmp = node->references;
-  node->referencesSize = newRefCount;
-  node->references = newRefs;
-  if (tmp)
-    UA_free(tmp);
-  
-  const UA_Node *inserted;
-  retval |= UA_NodeStore_replace(server->nodestore, (const UA_Node *) node, node, &inserted);
-  return retval;
+#endif
+
+    UA_NodeStore_release(orig);
+    return UA_STATUSCODE_GOOD;;
 }
 
 /* userland version of addReferenceWithSession */
@@ -716,16 +576,13 @@ UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *s
     return retval;
 } 
 
-/* userland version of addNodeWithSession */
-UA_AddNodesResult
-UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
-                  const UA_NodeId referenceTypeId) {
+UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
+                                    const UA_NodeId referenceTypeId) {
     return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
 }
 
-UA_AddNodesResult
-UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
-                             const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId) {
+UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
+                                               const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
 
@@ -847,7 +704,8 @@ UA_Server_addMethodNode(UA_Server* server, const UA_NodeId nodeId, const UA_Qual
      * UA_NULL; otherwise this is a pretty strong indicator that this node was generated,
      * in which case these arguments will be created later and individually.
      */
-    if (method == UA_NULL && inputArguments == UA_NULL && outputArguments == UA_NULL && inputArgumentsSize == 0 && outputArgumentsSize == 0)
+    if (method == UA_NULL && inputArguments == UA_NULL && outputArguments == UA_NULL &&
+        inputArgumentsSize == 0 && outputArgumentsSize == 0)
       return retval;
     
     /* create InputArguments */
@@ -884,8 +742,7 @@ UA_Server_addMethodNode(UA_Server* server, const UA_NodeId nodeId, const UA_Qual
     addRes = UA_Server_addNode(server, (UA_Node*)outputArgumentsVariableNode, methodExpandedNodeId,
                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
     UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
-    if(addRes.statusCode != UA_STATUSCODE_GOOD)
-    {
+    if(addRes.statusCode != UA_STATUSCODE_GOOD) {
         if(createdNodeId != UA_NULL)
             UA_NodeId_deleteMembers(createdNodeId);    	
         // TODO Remove node
@@ -895,21 +752,6 @@ UA_Server_addMethodNode(UA_Server* server, const UA_NodeId nodeId, const UA_Qual
     return retval;
 }
 #endif
-
-#define SETATTRIBUTE_ASSERTNODECLASS(CLASS) {                   \
-if ((anyTypeNode.node->nodeClass & ( CLASS )) == 0) {                     \
-    UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);          \
-    return UA_STATUSCODE_BADNODECLASSINVALID;                   \
-  }                                                             \
-}
-  
-#define SETATTRIBUTE_ASSERTTYPECORRECT(TYPE) { \
-  UA_NodeId expectedType = UA_NODEID_NUMERIC(0, UA_NS0ID_##TYPE); \
-  if (!UA_NodeId_equal(&dataType->typeId, &expectedType)) {       \
-    UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);            \
-    return UA_STATUSCODE_BADTYPEMISMATCH;                         \
-  }                                                               \
-}\
     
 UA_StatusCode UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId,
                                          const UA_AttributeId attributeId, const UA_Variant value) {
@@ -1003,202 +845,37 @@ UA_Server_setNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId,
   return retval;
 }
 
-#define SERVER_GETATTRIBUTE_COPYTYPEVALUE(TYPE, SRC) \
-  *value = (void *) UA_##TYPE##_new();               \
-  UA_##TYPE##_copy( SRC, (UA_##TYPE *) *value  );    \
-  
-UA_StatusCode UA_Server_getNodeAttribute(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void **value) {
-  union {
-    UA_Node *node;
-    UA_ObjectNode *oObj;
-    UA_ObjectTypeNode *otObj;
-    UA_VariableNode *vObj;
-    UA_VariableTypeNode *vtObj;
-    UA_ReferenceTypeNode *rtObj;
-    UA_MethodNode *mObj;
-    UA_DataTypeNode *dtObj;
-    UA_ViewNode *vwObj;
-  } anyTypeNode;
-  
-  UA_StatusCode retval = UA_Server_getNodeCopy(server, nodeId, (void **) &anyTypeNode.node);
-  if (retval != UA_STATUSCODE_GOOD)
-    return retval;
-  
-  switch(attributeId) {
-    case UA_ATTRIBUTEID_NODEID:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(NodeId, &anyTypeNode.node->nodeId);
-      break;
-    case UA_ATTRIBUTEID_NODECLASS:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(NodeClass, &anyTypeNode.node->nodeClass);
-      break;
-    case UA_ATTRIBUTEID_BROWSENAME:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(QualifiedName, &anyTypeNode.node->browseName);
-      break;
-    case UA_ATTRIBUTEID_DISPLAYNAME:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(LocalizedText, &anyTypeNode.node->displayName);
-      break;
-    case UA_ATTRIBUTEID_DESCRIPTION:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(LocalizedText, &anyTypeNode.node->description);
-      break;
-    case UA_ATTRIBUTEID_WRITEMASK:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(UInt32, &anyTypeNode.node->writeMask);
-      break;
-    case UA_ATTRIBUTEID_USERWRITEMASK:
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(UInt32, &anyTypeNode.node->userWriteMask);
-      break;    
-    case UA_ATTRIBUTEID_ISABSTRACT:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE)
-      switch(anyTypeNode.node->nodeClass) {
-        case UA_NODECLASS_OBJECTTYPE:
-          SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.otObj->isAbstract);
-          break;
-        case UA_NODECLASS_REFERENCETYPE:
-          SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.rtObj->isAbstract);
-          break;
-        case UA_NODECLASS_VARIABLETYPE:
-          SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.vtObj->isAbstract);
-          break;
-        case UA_NODECLASS_DATATYPE:
-          SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.dtObj->isAbstract);
-          break;
-        default:
-          UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-          return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-          break;
-      }
-      break;
-    case UA_ATTRIBUTEID_SYMMETRIC:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_REFERENCETYPE)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.rtObj->symmetric);
-      break;
-    case UA_ATTRIBUTEID_INVERSENAME:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_REFERENCETYPE)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(LocalizedText, &anyTypeNode.rtObj->inverseName);
-      break;
-    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VIEW)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.vwObj->containsNoLoops);
-      break;
-    case UA_ATTRIBUTEID_EVENTNOTIFIER:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT)
-      switch(anyTypeNode.node->nodeClass) {
-        case UA_NODECLASS_VIEW:
-          SERVER_GETATTRIBUTE_COPYTYPEVALUE(Byte, &anyTypeNode.vwObj->eventNotifier);
-          break;
-        case UA_NODECLASS_OBJECT:
-          SERVER_GETATTRIBUTE_COPYTYPEVALUE(Byte, &anyTypeNode.oObj->eventNotifier);
-          break;
-        default:
-          UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-          return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-          break;
-      }
-      break;
-    case UA_ATTRIBUTEID_VALUE:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE)
-      switch(anyTypeNode.node->nodeClass) {
-        case UA_NODECLASS_VARIABLE:
-          *value = UA_Variant_new();
-          if(anyTypeNode.vObj->valueSource == UA_VALUESOURCE_VARIANT) {
-            retval |= UA_Variant_copy(&anyTypeNode.vObj->value.variant, *value);
-          } else {
-            UA_DataValue ds;
-            UA_DataValue_init(&ds);
-            retval |= anyTypeNode.vObj->value.dataSource.read(anyTypeNode.vObj->value.dataSource.handle, UA_FALSE, UA_NULL, &ds);
-            UA_Variant_copy(&ds.value, *value);
-          }
-          break;
-        case UA_NODECLASS_VARIABLETYPE:
-          // Note: Precicely the same as variableNode above!
-          *value = UA_Variant_new();
-          if(anyTypeNode.vtObj->valueSource == UA_VALUESOURCE_VARIANT) {
-            retval |= UA_Variant_copy(&anyTypeNode.vtObj->value.variant, *value);
-          } else {
-            UA_DataValue ds;
-            UA_DataValue_init(&ds);
-            retval |= anyTypeNode.vtObj->value.dataSource.read(anyTypeNode.vtObj->value.dataSource.handle, UA_FALSE, UA_NULL, &ds);
-            UA_Variant_copy(&ds.value, *value);
-          }
-          break;
-        default:
-          UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-          return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-      }
-      break;
-    case UA_ATTRIBUTEID_DATATYPE:
-      UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-      return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-      break;
-    case UA_ATTRIBUTEID_VALUERANK:
-      UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-      return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-      break;
-    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
-      UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-      return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-      break;
-    case UA_ATTRIBUTEID_ACCESSLEVEL:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VARIABLE)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Byte, &anyTypeNode.vObj->accessLevel);
-      break;
-    case UA_ATTRIBUTEID_USERACCESSLEVEL:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VARIABLE)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Byte, &anyTypeNode.vObj->userAccessLevel);
-      break;
-    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VARIABLE)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Double, &anyTypeNode.vObj->minimumSamplingInterval);
-      break;
-    case UA_ATTRIBUTEID_HISTORIZING:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_VARIABLE)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.vObj->historizing);
-      break;
-    case UA_ATTRIBUTEID_EXECUTABLE:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_METHOD)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.mObj->executable);
-      break;
-    case UA_ATTRIBUTEID_USEREXECUTABLE:
-      SETATTRIBUTE_ASSERTNODECLASS(UA_NODECLASS_METHOD)
-      SERVER_GETATTRIBUTE_COPYTYPEVALUE(Boolean, &anyTypeNode.mObj->userExecutable);
-      break;
-    default:
-      UA_Server_deleteNodeCopy(server, (void **) &anyTypeNode.node);
-      return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-      break;
-  }
-  
-  return retval;
+UA_StatusCode UA_Server_getNodeAttribute(UA_Server *server, const UA_NodeId nodeId, UA_AttributeId attributeId, UA_Variant *v) {
+    const UA_ReadValueId rvi = {.nodeId = nodeId, .attributeId = attributeId, indexRange = UA_STRING_NULL,
+                                .dataEncoding = UA_QUALIFIEDNAME(0, "DefaultBinary")};
+    UA_DataValue dv;
+    UA_DataValue_init(&dv);
+    UA_StatusCode retval = Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER,
+                                               &rvi, &dv);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    *v = dv.value; // The caller needs to free the content eventually
+    return UA_STATUSCODE_GOOD;
 }
 
 #ifdef ENABLE_METHODCALLS
-UA_StatusCode UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback *method) {
-  union {
-    UA_Node *anyNode;
-    UA_MethodNode *mNode;
-  } node;
-  UA_StatusCode retval;
-  *method= UA_NULL;
-  
-  retval = UA_Server_getNodeCopy(server, methodNodeId, (void **) &node.anyNode);
-  if (retval != UA_STATUSCODE_GOOD || node.anyNode == UA_NULL)
-    return retval;
-  
-  if (node.anyNode->nodeClass != UA_NODECLASS_METHOD) {
-    UA_Server_deleteNodeCopy(server, (void **) &node);
-    return UA_STATUSCODE_BADNODECLASSINVALID;
-  }
-  
-  if (node.mNode->attachedMethod != UA_NULL) {
-    method = &node.mNode->attachedMethod;
-  }
-  
-  retval |= UA_Server_deleteNodeCopy(server, (void **) &node);
-  return retval;
+UA_StatusCode UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId nodeId, UA_MethodCallback *method) {
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
+    if(!node)
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+    
+    if(node.anyNode->nodeClass != UA_NODECLASS_METHOD) {
+        UA_NodeStore_release(node);
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+
+    *method = ((UA_MethodNode*)node)->attachToMethod;
+    UA_NodeStore_release(node);
+    return UA_STATUSCODE_GOOD;
 }
 #endif
 
-UA_StatusCode
-UA_Server_getNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource **value) {
+UA_StatusCode UA_Server_getNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource **value) {
   union {
     UA_Node *anyNode;
     UA_VariableNode *varNode;
@@ -1241,7 +918,6 @@ UA_Server_getNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId,
   return retval;
 }
 
-UA_StatusCode UA_Server_getAttributeValue(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void **value);
 #define arrayOfNodeIds_addNodeId(ARRAYNAME, NODEID) { \
   ARRAYNAME.size++; \
   ARRAYNAME.ids = UA_realloc(ARRAYNAME.ids, sizeof(UA_NodeId) * ARRAYNAME.size); \
@@ -1292,12 +968,12 @@ static void UA_Server_addInstanceOf_inheritParentAttributes(UA_Server *server, a
   return;
 }
 
-static void UA_Server_addInstanceOf_instatiateChildObject(UA_Server *server, 
-                                                          arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs, arrayOfNodeIds *typedefRefs,
-                                                          UA_Node *objectCopy, UA_NodeId parentId, UA_ExpandedNodeId typeDefinition, UA_NodeId referenceTypeId,
-                                                          UA_InstantiationCallback callback, UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes, 
-                                                          void *handle) 
-{
+static void UA_Server_addInstanceOf_instatiateChildObject(UA_Server *server, arrayOfNodeIds *subtypeRefs,
+                                                          arrayOfNodeIds *componentRefs, arrayOfNodeIds *typedefRefs,
+                                                          UA_Node *objectCopy, UA_NodeId parentId, UA_ExpandedNodeId typeDefinition,
+                                                          UA_NodeId referenceTypeId, UA_InstantiationCallback callback,
+                                                          UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes, 
+                                                          void *handle) {
   UA_StatusCode retval = UA_STATUSCODE_GOOD;
   
   // Refuse to create this node if we detect a circular type definition
@@ -1320,9 +996,9 @@ static void UA_Server_addInstanceOf_instatiateChildObject(UA_Server *server,
   
   // Create the object root as specified by the user
   UA_NodeId objectRoot;
-  retval |= UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(parentId.namespaceIndex, 0), objectCopy->browseName, objectCopy->displayName, 
-                                    objectCopy->description, objectCopy->userWriteMask, objectCopy->writeMask,
-                                      parentId, referenceTypeId, typeDefinition, &objectRoot);
+  retval |= UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(parentId.namespaceIndex, 0), objectCopy->browseName,
+                                    objectCopy->displayName, objectCopy->description, objectCopy->userWriteMask,
+                                    objectCopy->writeMask, parentId, referenceTypeId, typeDefinition, &objectRoot);
   if (retval)
     return;
   
@@ -1342,11 +1018,10 @@ static void UA_Server_addInstanceOf_instatiateChildObject(UA_Server *server,
   return;
 }
   
-void UA_Server_addInstanceOf_instatiateChildNode(UA_Server *server, 
-                                                arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs, arrayOfNodeIds *typedefRefs,
-                                                UA_NodeId objectRoot, UA_InstantiationCallback callback, void *typeDefNode,
-                                                UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes, void *handle) 
-{
+void UA_Server_addInstanceOf_instatiateChildNode(UA_Server *server, arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs,
+                                                 arrayOfNodeIds *typedefRefs, UA_NodeId objectRoot, UA_InstantiationCallback callback,
+                                                 void *typeDefNode, UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes,
+                                                 void *handle) {
   UA_Boolean refTypeValid;
   UA_NodeClass *refClass;
   UA_Node      *nodeClone;

+ 2 - 6
src/server/ua_services.h

@@ -202,12 +202,8 @@ UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range);
  */
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
                   UA_ReadResponse *response);
-
-/* Mock-Up of the function signature for Unit Tests */
-#ifdef BUILD_UNIT_TESTS
-void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
-                      const UA_ReadValueId *id, UA_DataValue *v);
-#endif
+void Service_Read_single(UA_Server *server, UA_Session *session, UA_TimestampsToReturn timestamps,
+                         const UA_ReadValueId *id, UA_DataValue *v);
 
 // Service_HistoryRead
 /**

+ 9 - 13
src/server/ua_services_attribute.c

@@ -95,10 +95,8 @@ static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValu
 }
 
 /** Reads a single attribute from a node in the nodestore. */
-#ifndef BUILD_UNIT_TESTS
-static
-#endif
-void readValue(UA_Server *server, UA_TimestampsToReturn timestamps, const UA_ReadValueId *id, UA_DataValue *v) {
+void Service_Read_single(UA_Server *server, UA_Session *session, UA_TimestampsToReturn timestamps,
+                         const UA_ReadValueId *id, UA_DataValue *v) {
     UA_String binEncoding = UA_STRING("DefaultBinary");
     UA_String xmlEncoding = UA_STRING("DefaultXml");
 	if(id->dataEncoding.name.length >= 0){
@@ -260,7 +258,8 @@ void readValue(UA_Server *server, UA_TimestampsToReturn timestamps, const UA_Rea
         {
             const UA_VariableNode *vn = (const UA_VariableNode *)node;
             if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-                retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.arrayDimensions, vn->value.variant.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+                retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.arrayDimensions,
+                                                 vn->value.variant.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
                 if(retval == UA_STATUSCODE_GOOD)
                     v->hasValue = UA_TRUE;
             } else {
@@ -269,7 +268,8 @@ void readValue(UA_Server *server, UA_TimestampsToReturn timestamps, const UA_Rea
                 retval |= vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, UA_NULL, &val);
                 if(retval != UA_STATUSCODE_GOOD)
                     break;
-                retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions, val.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+                retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions, val.value.arrayDimensionsSize,
+                                                 &UA_TYPES[UA_TYPES_INT32]);
                 UA_DataValue_deleteMembers(&val);
             }
         }
@@ -290,7 +290,8 @@ void readValue(UA_Server *server, UA_TimestampsToReturn timestamps, const UA_Rea
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->minimumSamplingInterval, &UA_TYPES[UA_TYPES_DOUBLE]);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->minimumSamplingInterval,
+                                           &UA_TYPES[UA_TYPES_DOUBLE]);
         break;
 
     case UA_ATTRIBUTEID_HISTORIZING:
@@ -356,13 +357,8 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
 
 #ifdef UA_EXTERNAL_NAMESPACES
-#ifdef NO_ALLOCA
     UA_Boolean isExternal[size];
     UA_UInt32 indices[size];
-#else
-    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
-    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-#endif /*NO_ALLOCA */
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     for(size_t j = 0;j<server->externalNamespacesSize;j++) {
         size_t indexSize = 0;
@@ -385,7 +381,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
-            readValue(server, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]);
+            Service_Read_single(server, session, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]);
     }
 
 #ifdef EXTENSION_STATELESS