Bläddra i källkod

add a unit test for node management; add hastypedefinition for instantiated nodes

Julius Pfrommer 9 år sedan
förälder
incheckning
b3dbefaa51

+ 6 - 4
examples/server.c

@@ -319,28 +319,30 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
-                            UA_NODEID_NULL, object_attr);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
 
 #define SCALARID 50001
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Scalar");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                            UA_QUALIFIEDNAME(1, "Scalar"), UA_NODEID_NULL, object_attr);
+                            UA_QUALIFIEDNAME(1, "Scalar"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
 
 #define ARRAYID 50002
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Array");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                            UA_QUALIFIEDNAME(1, "Array"), UA_NODEID_NULL, object_attr);
+                            UA_QUALIFIEDNAME(1, "Array"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
 
 #define MATRIXID 50003
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
-                            UA_NODEID_NULL, object_attr);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr);
 
     UA_UInt32 id = 51000; // running id in namespace 0
     for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {

+ 1 - 1
src/server/ua_server.c

@@ -103,7 +103,7 @@ UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
 }
 
 UA_StatusCode UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
-    return Service_DeleteNodes_single(server, &adminSession, nodeId, UA_TRUE);
+    return Service_DeleteNodes_single(server, &adminSession, &nodeId, UA_TRUE);
 }
 
 UA_StatusCode

+ 1 - 1
src/server/ua_services.h

@@ -120,7 +120,7 @@ UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *sessio
 /** Used to delete one or more Nodes from the AddressSpace. */
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
                          UA_DeleteNodesResponse *response);
-UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId nodeId,
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId *nodeId,
                                          UA_Boolean deleteReferences);
 
 /** Used to delete one or more References of a Node. */

+ 9 - 9
src/server/ua_services_attribute.c

@@ -223,27 +223,27 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
     case UA_ATTRIBUTEID_ISABSTRACT:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE |
                         UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->isAbstract,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_SYMMETRIC:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->symmetric,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_INVERSENAME:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->inverseName,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
                                           &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode *)node)->containsNoLoops,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode *)node)->eventNotifier,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
                                           &UA_TYPES[UA_TYPES_BYTE]);
         break;
     case UA_ATTRIBUTEID_VALUE:
@@ -256,7 +256,7 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
         break;
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode *)node)->valueRank,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
                                            &UA_TYPES[UA_TYPES_INT32]);
         break;
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
@@ -280,17 +280,17 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
         break;
     case UA_ATTRIBUTEID_HISTORIZING:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->historizing,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->historizing,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_EXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode *)node)->executable,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->executable,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     case UA_ATTRIBUTEID_USEREXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode *)node)->userExecutable,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->userExecutable,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
     default:

+ 52 - 21
src/server/ua_services_nodemanagement.c

@@ -84,11 +84,11 @@ void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *
 }
 
 static UA_StatusCode
-instantiateVariable(UA_Server *server, UA_Session *session,
-                    const UA_NodeId *nodeId, const UA_NodeId *typeId);
+instantiateVariableNode(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);
+instantiateObjectNode(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. */
@@ -143,7 +143,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
         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);
+        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
     }
 
     UA_AddNodesResult_deleteMembers(&res);
@@ -195,7 +195,7 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
         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);
+        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
     }
 
     UA_AddNodesResult_deleteMembers(&res);
@@ -204,11 +204,11 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
 }
 
 static UA_StatusCode
-instantiateObject(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+instantiateObjectNode(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) {
+    if(type->nodeClass != UA_NODECLASS_OBJECTTYPE) {
         UA_NodeStore_release((const UA_Node*)type);
         return UA_STATUSCODE_BADNODECLASSINVALID;
     }
@@ -247,6 +247,16 @@ instantiateObject(UA_Server *server, UA_Session *session, const UA_NodeId *nodeI
     }
     UA_NodeStore_release((const UA_Node*)type);
 
+    /* add a hastypedefinition reference */
+    UA_AddReferencesItem addref;
+    UA_AddReferencesItem_init(&addref);
+    addref.sourceNodeId = *nodeId;
+    addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+    addref.isForward = UA_TRUE;
+    addref.targetNodeId.nodeId = *typeId;
+    addref.targetNodeClass = UA_NODECLASS_OBJECTTYPE;
+    Service_AddReferences_single(server, session, &addref);
+
     /* call the constructor */
     /* void *instanceHandle = */
     /*     ((const UA_ObjectTypeNode*)parent)->instanceManagement.constructor(result->addedNodeId); */
@@ -259,17 +269,16 @@ instantiateObject(UA_Server *server, UA_Session *session, const UA_NodeId *nodeI
 }
 
 static UA_StatusCode
-instantiateVariable(UA_Server *server, UA_Session *session,
-                    const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+instantiateVariableNode(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) {
+    if(type->nodeClass != UA_NODECLASS_VARIABLETYPE) {
         UA_NodeStore_release((const UA_Node*)type);
         return UA_STATUSCODE_BADNODECLASSINVALID;
     }
 
-    /* Add all the child nodes */
+    /* get the references to child properties */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
     browseChildren.nodeId = *typeId;
@@ -284,11 +293,23 @@ instantiateVariable(UA_Server *server, UA_Session *session,
     // todo: continuation points if there are too many results
     Service_Browse_single(server, session, UA_NULL, &browseChildren, 100, &browseResult);
 
+    /* add the child properties */
     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);
+
+    /* add a hastypedefinition reference */
+    UA_AddReferencesItem addref;
+    UA_AddReferencesItem_init(&addref);
+    addref.sourceNodeId = *nodeId;
+    addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+    addref.isForward = UA_TRUE;
+    addref.targetNodeId.nodeId = *typeId;
+    addref.targetNodeClass = UA_NODECLASS_OBJECTTYPE;
+    Service_AddReferences_single(server, session, &addref);
+
     return UA_STATUSCODE_GOOD;
 }
 
@@ -393,6 +414,7 @@ dataTypeNodeFromAttributes(UA_AddNodesItem *item, UA_DataTypeAttributes *attr) {
 
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
                              UA_NodeAttributes *attr, UA_AddNodesResult *result) {
+    /* create the node */
     UA_Node *node;
     switch(item->nodeClass) {
     case UA_NODECLASS_OBJECT:
@@ -428,16 +450,25 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodes
         return;
     }
 
+    /* add it to the server */
     UA_Server_addExistingNode(server, session, node, &item->parentNodeId.nodeId,
                               &item->referenceTypeId, result);
     if(result->statusCode != UA_STATUSCODE_GOOD) {
         UA_Node_deleteAnyNodeClass(node);
         return;
     }
-    if(item->nodeClass == UA_NODECLASS_OBJECT)
-        result->statusCode = instantiateObject(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
-    else if(item->nodeClass == UA_NODECLASS_VARIABLE)
-        result->statusCode = instantiateVariable(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
+
+    /* instantiate if it has a type */
+    if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
+        if(item->nodeClass == UA_NODECLASS_OBJECT)
+            result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
+        else if(item->nodeClass == UA_NODECLASS_VARIABLE)
+            result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
+    }
+
+    /* if instantiation failed, remove the node */
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        Service_DeleteNodes_single(server, session, &result->addedNodeId, UA_TRUE);
 }
 
 static void Service_AddNodes_single_unparsed(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
@@ -797,16 +828,16 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
 // TODO: Check consistency constraints, remove the references.
 
-UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId nodeId,
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId *nodeId,
                                          UA_Boolean deleteReferences) {
-    const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(deleteReferences == UA_TRUE) {
         UA_DeleteReferencesItem delItem;
         UA_DeleteReferencesItem_init(&delItem);
         delItem.deleteBidirectional = UA_FALSE;
-        UA_NodeId_copy(&nodeId, &delItem.targetNodeId.nodeId);
+        UA_NodeId_copy(nodeId, &delItem.targetNodeId.nodeId);
         for(int i = 0; i < node->referencesSize; i++) {
             delItem.sourceNodeId = node->references[i].targetId.nodeId;
             delItem.isForward = node->references[i].isInverse;
@@ -816,7 +847,7 @@ UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
         UA_DeleteReferencesItem_deleteMembers(&delItem);
     }
     UA_NodeStore_release(node);
-    return UA_NodeStore_remove(server->nodestore, &nodeId);
+    return UA_NodeStore_remove(server->nodestore, nodeId);
 }
 
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
@@ -833,7 +864,7 @@ void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_Delete
     response->resultsSize = request->nodesToDeleteSize;
     for(int i=0; i<request->nodesToDeleteSize; i++) {
         UA_DeleteNodesItem *item = &request->nodesToDelete[i];
-        response->results[i] = Service_DeleteNodes_single(server, session, item->nodeId,
+        response->results[i] = Service_DeleteNodes_single(server, session, &item->nodeId,
                                                           item->deleteTargetReferences);
     }
 }

+ 4 - 2
tests/CMakeLists.txt

@@ -46,12 +46,14 @@ add_executable(check_services_attributes check_services_attributes.c $<TARGET_OB
 target_link_libraries(check_services_attributes ${LIBS})
 add_test(services_attributes ${CMAKE_CURRENT_BINARY_DIR}/check_services_attributes)
 
+add_executable(check_services_nodemanagement check_services_nodemanagement.c $<TARGET_OBJECTS:open62541-object>)
+target_link_libraries(check_services_nodemanagement ${LIBS})
+add_test(services_nodemanagement ${CMAKE_CURRENT_BINARY_DIR}/check_services_nodemanagement)
+
 add_executable(check_nodestore check_nodestore.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_nodestore ${LIBS})
 add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 
-
-
 add_executable(check_session check_session.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_session ${LIBS})
 add_test(session ${CMAKE_CURRENT_BINARY_DIR}/check_session)

+ 1 - 0
tests/check_services_attributes.c

@@ -354,6 +354,7 @@ START_TEST(ReadSingleAttributeEventNotifierWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(1, 50);
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(UA_STATUSCODE_GOOD, resp.status);
     ck_assert_int_eq(-1, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE],resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);