Browse Source

refactor: simplify object and variable instantiation

Julius Pfrommer 8 years ago
parent
commit
7643772e25

+ 2 - 2
src/server/ua_server_internal.h

@@ -132,8 +132,8 @@ getObjectNodeType(UA_Server *server, const UA_ObjectNode *node);
  * hasSubType reference. Since multi-inheritance is possible, we test for
  * duplicates and return evey nodeid at most once. */
 UA_StatusCode
-getTypeHierarchy(UA_NodeStore *ns, const UA_Node *root,
-                 UA_NodeId **reftypes, size_t *reftypes_count);
+getTypeHierarchy(UA_NodeStore *ns, const UA_Node *rootRef, UA_Boolean inverse,
+                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize);
 
 UA_StatusCode
 isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode,

+ 5 - 5
src/server/ua_server_utils.c

@@ -82,27 +82,27 @@ parse_numericrange(const UA_String *str, UA_NumericRange *range) {
 /********************************/
 
 UA_StatusCode
-getTypeHierarchy(UA_NodeStore *ns, const UA_Node *root,
+getTypeHierarchy(UA_NodeStore *ns, const UA_Node *rootRef, UA_Boolean inverse,
                  UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
     size_t results_size = 20; // probably too big, but saves mallocs
     UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
     if(!results)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
-    UA_StatusCode retval = UA_NodeId_copy(&root->nodeId, &results[0]);
+    UA_StatusCode retval = UA_NodeId_copy(&rootRef->nodeId, &results[0]);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_free(results);
         return retval;
     }
 
-    const UA_Node *node = root;
+    const UA_Node *node = rootRef;
     size_t idx = 0; /* Current index (contains NodeId of node) */
     size_t last = 0; /* Index of the last element in the array */
     const UA_NodeId hasSubtypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
     while(true) {
         for(size_t i = 0; i < node->referencesSize; i++) {
             /* is the reference relevant? */
-            if(node->references[i].isInverse == true ||
+            if(node->references[i].isInverse != inverse ||
                !UA_NodeId_equal(&hasSubtypeNodeId, &node->references[i].referenceTypeId))
                 continue;
 
@@ -141,7 +141,7 @@ getTypeHierarchy(UA_NodeStore *ns, const UA_Node *root,
         if(idx > last || retval != UA_STATUSCODE_GOOD)
             break;
         node = UA_NodeStore_get(ns, &results[idx]);
-        if(!node || node->nodeClass != root->nodeClass)
+        if(!node || node->nodeClass != rootRef->nodeClass)
             goto next;
     }
 

+ 77 - 159
src/server/ua_services_nodemanagement.c

@@ -71,8 +71,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     
     /* Copy any aggregated/nested variables/methods/subobjects this object contains 
-     * These objects may not be part of the nodes type.
-     */
+     * These objects may not be part of the nodes type. */
     copyChildNodesToNode(server, session, &node->nodeId, &res.addedNodeId, instantiationCallback);
     if(instantiationCallback)
         instantiationCallback->method(res.addedNodeId, node->nodeId, 
@@ -125,8 +124,7 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *obje
     Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     
     /* Copy any aggregated/nested variables/methods/subobjects this object contains 
-     * These objects may not be part of the nodes type.
-     */
+     * These objects may not be part of the nodes type. */
     copyChildNodesToNode(server, session, &node->nodeId, &res.addedNodeId, instantiationCallback);
     if(instantiationCallback)
         instantiationCallback->method(res.addedNodeId, node->nodeId, 
@@ -148,138 +146,62 @@ setObjectInstanceHandle(UA_Server *server, UA_Session *session,
 }
 
 static UA_StatusCode
-instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId, size_t depth,
-                      UA_InstantiationCallback *instantiationCallback) {
-    /* see if the type is derived from baseobjecttype */
-    UA_Boolean found = false;
-    const UA_NodeId hassubtype = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
-    const UA_NodeId baseobjtype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
-    UA_StatusCode retval = isNodeInTree(server->nodestore, typeId,
-                                        &baseobjtype, &hassubtype, 1, &found);
-    if(!found || retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG_SESSION(server->config.logger, session,
-                             "AddNodes: The object if not derived from BaseObjectType");
-        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
-    }
-
+instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                UA_NodeClass nodeClass, const UA_NodeId *typeId,
+                UA_InstantiationCallback *instantiationCallback) {
     /* see if the type node is correct */
-    const UA_ObjectTypeNode *typenode =
-        (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
-    if(!typenode || typenode->nodeClass != UA_NODECLASS_OBJECTTYPE || typenode->isAbstract)
+    const UA_Node *typenode = UA_NodeStore_get(server->nodestore, typeId);
+    if(!typenode)
         return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
-
-    /* Add all the child nodes */
-    copyChildNodesToNode(server, session, typeId, nodeId, instantiationCallback);
-    
-    /* Instantiate supertype attributes if a supertype is available */
-    UA_BrowseDescription browseChildren;
-    UA_BrowseDescription_init(&browseChildren);
-    browseChildren.nodeId = *typeId;
-    browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
-    browseChildren.includeSubtypes = false;
-    browseChildren.browseDirection = UA_BROWSEDIRECTION_INVERSE; // isSubtypeOf
-    browseChildren.nodeClassMask = UA_NODECLASS_OBJECTTYPE;
-    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, NULL, &browseChildren, 100, &browseResult);
-    for(size_t i = 0; i < browseResult.referencesSize; i++) {
-        UA_ReferenceDescription *rd = &browseResult.references[i];
-        instantiateObjectNode(server, session, nodeId, &rd->nodeId.nodeId,
-                              depth+1, instantiationCallback);
-    }
-    UA_BrowseResult_deleteMembers(&browseResult);
-    
-    /* add a hastypedefinition reference */
-    if(depth == 0) {
-        UA_AddReferencesItem addref;
-        UA_AddReferencesItem_init(&addref);
-        addref.sourceNodeId = *nodeId;
-        addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
-        addref.isForward = true;
-        addref.targetNodeId.nodeId = *typeId;
-        addref.targetNodeClass = UA_NODECLASS_OBJECTTYPE;
-        Service_AddReferences_single(server, session, &addref);
-    }
-
-    /* call the constructor */
-    const UA_ObjectLifecycleManagement *olm = &typenode->lifecycleManagement;
-    if(olm->constructor)
-        UA_Server_editNode(server, session, nodeId,
-                           (UA_EditNodeCallback)setObjectInstanceHandle,
-                           olm->constructor);
-    return UA_STATUSCODE_GOOD;
-}
-
-static UA_StatusCode
-instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                        const UA_NodeId *typeId, size_t depth,
-                        UA_InstantiationCallback *instantiationCallback) {
-    /* see if the type is derived from basevariabletype */
-    UA_Boolean found = false;
-    const UA_NodeId hassubtype = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
-    const UA_NodeId basevartype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE);
-    UA_StatusCode retval = isNodeInTree(server->nodestore, typeId,
-                                        &basevartype, &hassubtype, 1, &found);
-    if(!found || retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG_SESSION(server->config.logger, session,
-                             "AddNodes: The variable is not derived from BaseVariableType");
+    if(nodeClass == UA_NODECLASS_VARIABLE) {
+        if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE ||
+           ((const UA_VariableTypeNode*)typenode)->isAbstract)
+            return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+    } else if(nodeClass == UA_NODECLASS_OBJECT) {
+        if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE ||
+           ((const UA_ObjectTypeNode*)typenode)->isAbstract)
+            return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+    } else {
         return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
     }
 
-    /* see if the type is correct */
-    const UA_VariableTypeNode *typenode =
-        (const UA_VariableTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
-    if(!typenode || typenode->nodeClass != UA_NODECLASS_VARIABLETYPE || typenode->isAbstract)
-        return UA_STATUSCODE_BADNODEIDINVALID;
-
-    /* get the references to child properties */
-    /* Add all the child nodes */
-    copyChildNodesToNode(server, session, typeId, nodeId, instantiationCallback);
+    /* Get the hierarchy of the type and all its supertypes */
+    UA_NodeId *hierarchy = NULL;
+    size_t hierarchySize = 0;
+    UA_StatusCode retval =
+        getTypeHierarchy(server->nodestore, typenode, true, &hierarchy, &hierarchySize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
     
-    /* Instantiate supertypes */
-    UA_BrowseDescription browseChildren;
-    UA_BrowseDescription_init(&browseChildren);
-    browseChildren.nodeId = *typeId;
-    browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
-    browseChildren.includeSubtypes = false;
-    browseChildren.browseDirection = UA_BROWSEDIRECTION_INVERSE; // isSubtypeOf
-    browseChildren.nodeClassMask = UA_NODECLASS_VARIABLETYPE;
-    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, NULL, &browseChildren, 100, &browseResult);
-    for(size_t i = 0; i < browseResult.referencesSize; i++) {
-        UA_ReferenceDescription *rd = &browseResult.references[i];
-        instantiateVariableNode(server, session, nodeId, &rd->nodeId.nodeId,
-                                depth+1, instantiationCallback);
-    }
-    UA_BrowseResult_deleteMembers(&browseResult);
+    /* Copy members of the type and supertypes */
+    for(size_t i = 0; i < hierarchySize; i++)
+        retval |= copyChildNodesToNode(server, session, &hierarchy[i], nodeId, instantiationCallback);
+    UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
 
-    /* add a hastypedefinition reference */
-    if(depth == 0) {
-        UA_AddReferencesItem addref;
-        UA_AddReferencesItem_init(&addref);
-        addref.sourceNodeId = *nodeId;
-        addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
-        addref.isForward = true;
-        addref.targetNodeId.nodeId = *typeId;
-        addref.targetNodeClass = UA_NODECLASS_OBJECTTYPE;
-        /* TODO: Check result */
-        Service_AddReferences_single(server, session, &addref);
+    /* Call the object constructor */
+    if(typenode->nodeClass == UA_NODECLASS_OBJECTTYPE) {
+        const UA_ObjectLifecycleManagement *olm =
+            &((const UA_ObjectTypeNode*)typenode)->lifecycleManagement;
+        if(olm->constructor)
+            UA_Server_editNode(server, session, nodeId,
+                               (UA_EditNodeCallback)setObjectInstanceHandle,
+                               olm->constructor);
     }
 
-    return UA_STATUSCODE_GOOD;
-} 
+    /* Add a hasType reference */
+    UA_AddReferencesItem addref;
+    UA_AddReferencesItem_init(&addref);
+    addref.sourceNodeId = *nodeId;
+    addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+    addref.isForward = true;
+    addref.targetNodeId.nodeId = *typeId;
+    return Service_AddReferences_single(server, session, &addref);
+}
 
 /* Search for an instance of "browseName" in node searchInstance
- * Used during copyChildNodes to find overwritable/mergable nodes
- */
+ * Used during copyChildNodes to find overwritable/mergable nodes */
 static UA_NodeId
 instanceFindAggregateByBrowsename(UA_Server *server, UA_Session *session, 
                                   const UA_NodeId *searchInstance, 
@@ -332,7 +254,8 @@ copyChildNodesToNode(UA_Server* server, UA_Session* session,
     browseChildren.includeSubtypes = 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_BROWSERESULTMASK_BROWSENAME;
+    browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS |
+        UA_BROWSERESULTMASK_BROWSENAME;
   
     UA_BrowseResult browseResult;
     UA_BrowseResult_init(&browseResult);
@@ -342,7 +265,8 @@ copyChildNodesToNode(UA_Server* server, UA_Session* session,
     for(size_t i = 0; i < browseResult.referencesSize; i++) {
         UA_ReferenceDescription *rd = &browseResult.references[i];
         // Check for deduplication
-        UA_NodeId existing = instanceFindAggregateByBrowsename(server, session, destinationNodeId, &rd->browseName);
+        UA_NodeId existing = instanceFindAggregateByBrowsename(server, session, destinationNodeId,
+                                                               &rd->browseName);
         if(UA_NodeId_equal(&UA_NODEID_NULL, &existing)) { /* New node in child */
             if(rd->nodeClass == UA_NODECLASS_METHOD) {
                 /* add a reference to the method in the objecttype */
@@ -362,15 +286,17 @@ copyChildNodesToNode(UA_Server* server, UA_Session* session,
                                    &rd->referenceTypeId, destinationNodeId, instantiationCallback);
         } else { /* Preexistent node in child */
             /* General strategy if we meet an already existing node:
-             * - Preexistent variable contents always 'win' overwriting anything supertypes would instantiate
-             * - Always copy contents of template *into* existant node (merge contents of e.g. Folders like ParameterSet)
-             */
+             * - Preexistent variable contents always 'win' overwriting anything
+             *   supertypes would instantiate
+             * - Always copy contents of template *into* existant node (merge
+             *   contents of e.g. Folders like ParameterSet) */
             if(rd->nodeClass == UA_NODECLASS_METHOD) {
                 /* Do nothing, existent method wins */
             } else if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
                       rd->nodeClass == UA_NODECLASS_OBJECT) {
                 if(!UA_NodeId_equal(&rd->nodeId.nodeId, &existing))
-                    copyChildNodesToNode(server, session, &rd->nodeId.nodeId, &existing, instantiationCallback);
+                    copyChildNodesToNode(server, session, &rd->nodeId.nodeId,
+                                         &existing, instantiationCallback);
             }
         }
     }
@@ -463,19 +389,6 @@ Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
         return UA_STATUSCODE_BADNODEIDINVALID;
     }
 
-    /* Fall back to a default typedefinition for variables and objects */
-    const UA_NodeId basedatavariabletype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
-    const UA_NodeId baseobjecttype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
-    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
-       node->nodeClass == UA_NODECLASS_OBJECT) {
-        if(!typeDefinition || UA_NodeId_isNull(typeDefinition)) {
-            if(node->nodeClass == UA_NODECLASS_VARIABLE)
-                typeDefinition = &basedatavariabletype;
-            else
-                typeDefinition = &baseobjecttype;
-        }
-    }
-
     /* Check the reference to the parent */
     UA_StatusCode retval = checkParentReference(server, session, node->nodeClass,
                                                 parentNodeId, referenceTypeId);
@@ -517,17 +430,26 @@ Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
         goto remove_node;
     }
 
-    /* Instantiate variables and objects */
-    if(node->nodeClass == UA_NODECLASS_OBJECT)
-        retval = instantiateObjectNode(server, session, &node->nodeId,
-                                       typeDefinition, 0, instantiationCallback);
-    else if(node->nodeClass == UA_NODECLASS_VARIABLE)
-        retval = instantiateVariableNode(server, session, &node->nodeId,
-                                         typeDefinition, 0, instantiationCallback);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG_SESSION(server->config.logger, session,
-                             "AddNodes: Could not instantiate the node");
-        goto remove_node;
+    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+       node->nodeClass == UA_NODECLASS_OBJECT) {
+        /* Fall back to a default typedefinition for variables and objects */
+        const UA_NodeId basedatavariabletype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+        const UA_NodeId baseobjecttype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
+        if(!typeDefinition || UA_NodeId_isNull(typeDefinition)) {
+            if(node->nodeClass == UA_NODECLASS_VARIABLE)
+                typeDefinition = &basedatavariabletype;
+            else
+                typeDefinition = &baseobjecttype;
+        }
+
+        /* Instantiate variables and objects */
+        retval = instantiateNode(server, session, &node->nodeId, node->nodeClass,
+                                 typeDefinition, instantiationCallback);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_DEBUG_SESSION(server->config.logger, session,
+                                 "AddNodes: Could not instantiate the node");
+            goto remove_node;
+        }
     }
 
     /* Custom callback */
@@ -587,10 +509,6 @@ copyCommonVariableAttributes(UA_Server *server, UA_VariableNode *node,
     if(!UA_NodeId_isNull(&attr->dataType))
         retval  = UA_VariableNode_setDataType(server, node, vt, &attr->dataType);
     else /* workaround common error where the datatype is left as NA_NODEID_NULL */
-      /* Note that most NS0 VarTypeNodes are DataTypes, not VariableTypes! */
-      if (vt->nodeClass == UA_NODECLASS_DATATYPE) 
-        UA_NodeId_copy(&vt->nodeId, &node->dataType);
-      else
         retval = UA_VariableNode_setDataType(server, node, vt, &vt->dataType);
         
     node->valueRank = -2; /* allow all dimensions first */

+ 2 - 2
src/server/ua_services_view.c

@@ -176,7 +176,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session,
             return;
         }
         if(descr->includeSubtypes) {
-            result->statusCode = getTypeHierarchy(server->nodestore, rootRef,
+            result->statusCode = getTypeHierarchy(server->nodestore, rootRef, false,
                                                   &relevant_refs, &relevant_refs_size);
             if(result->statusCode != UA_STATUSCODE_GOOD)
                 return;
@@ -429,7 +429,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
         const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &elem->referenceTypeId);
         if(!rootRef || rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE)
             return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-        retval = getTypeHierarchy(server->nodestore, rootRef, &reftypes, &reftypes_count);
+        retval = getTypeHierarchy(server->nodestore, rootRef, false, &reftypes, &reftypes_count);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
     }