static UA_Server* makeTestSequence(void) { UA_Server *server = UA_Server_new(UA_ServerConfig_standard); /* VariableNode */ UA_Variant *myIntegerVariant = UA_Variant_new(); UA_Int32 myInteger = 42; UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]); const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, UA_LOCALIZEDTEXT("en_US","the answer"), UA_LOCALIZEDTEXT("en_US","the answer"), 0, 0, parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL); /* ObjectNode */ UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 50), UA_QUALIFIEDNAME(1, "Demo"), UA_LOCALIZEDTEXT("en_US","Demo"), UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL); /* ReferenceTypeNode */ UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new(); copyNames((UA_Node*)organizes, "Organizes"); organizes->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "OrganizedBy"); organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES; organizes->isAbstract = UA_FALSE; organizes->symmetric = UA_FALSE; UA_Server_addNode(server, (UA_Node*)organizes, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)); /* ViewNode */ UA_ViewNode *viewtest = UA_ViewNode_new(); copyNames((UA_Node*)viewtest, "Viewtest"); viewtest->nodeId.identifier.numeric = UA_NS0ID_VIEWNODE; UA_Server_addNode(server, (UA_Node*)viewtest, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)); /* MethodNode */ UA_MethodNode *methodtest = UA_MethodNode_new(); copyNames((UA_Node*)methodtest, "Methodtest"); methodtest->nodeId.identifier.numeric = UA_NS0ID_METHODNODE; UA_Server_addNode(server, (UA_Node*)methodtest, UA_EXPANDEDNODEID_NUMERIC(0, 3), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)); return server; }
/* Adds a one-way reference to the local nodestore */ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) { const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId); if(!node) return UA_STATUSCODE_BADINTERNALERROR; UA_StatusCode retval = UA_STATUSCODE_GOOD; #ifndef UA_MULTITHREADING size_t i = node->referencesSize; if(node->referencesSize < 0) i = 0; size_t refssize = (i+1) | 3; // so the realloc is not necessary every time UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize); if(!new_refs) retval = UA_STATUSCODE_BADOUTOFMEMORY; else { UA_ReferenceNode_init(&new_refs[i]); retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId); new_refs[i].isInverse = !item->isForward; retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId); /* hack. be careful! possible only in the single-threaded case. */ UA_Node *mutable_node = (UA_Node*)(uintptr_t)node; mutable_node->references = new_refs; if(retval != UA_STATUSCODE_GOOD) { UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId); UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId); } else mutable_node->referencesSize = i+1; } UA_NodeStore_release(node); return retval; #else UA_Node *newNode = UA_NULL; void (*deleteNode)(UA_Node*) = UA_NULL; switch(node->nodeClass) { case UA_NODECLASS_OBJECT: newNode = (UA_Node*)UA_ObjectNode_new(); UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete; break; case UA_NODECLASS_VARIABLE: newNode = (UA_Node*)UA_VariableNode_new(); UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete; break; case UA_NODECLASS_METHOD: newNode = (UA_Node*)UA_MethodNode_new(); UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete; break; case UA_NODECLASS_OBJECTTYPE: newNode = (UA_Node*)UA_ObjectTypeNode_new(); UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete; break; case UA_NODECLASS_VARIABLETYPE: newNode = (UA_Node*)UA_VariableTypeNode_new(); UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete; break; case UA_NODECLASS_REFERENCETYPE: newNode = (UA_Node*)UA_ReferenceTypeNode_new(); UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete; break; case UA_NODECLASS_DATATYPE: newNode = (UA_Node*)UA_DataTypeNode_new(); UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete; break; case UA_NODECLASS_VIEW: newNode = (UA_Node*)UA_ViewNode_new(); UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode); deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete; break; default: return UA_STATUSCODE_BADINTERNALERROR; } UA_Int32 count = node->referencesSize; if(count < 0) count = 0; UA_ReferenceNode *old_refs = newNode->references; UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1)); if(!new_refs) { deleteNode(newNode); UA_NodeStore_release(node); return UA_STATUSCODE_BADOUTOFMEMORY; } // insert the new reference UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count); UA_ReferenceNode_init(&new_refs[count]); retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId); new_refs[count].isInverse = !item->isForward; retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId); if(retval != UA_STATUSCODE_GOOD) { UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count); newNode->references = UA_NULL; newNode->referencesSize = 0; deleteNode(newNode); UA_NodeStore_release(node); return UA_STATUSCODE_BADOUTOFMEMORY; } UA_free(old_refs); newNode->references = new_refs; newNode->referencesSize = ++count; retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL); UA_NodeStore_release(node); if (retval == UA_STATUSCODE_BADINTERNALERROR) { /* presumably because the node was replaced and an old version was updated at the same time. just try again */ deleteNode(newNode); return addOneWayReferenceWithSession(server, session, item); } return retval; #endif }
UA_StatusCode UA_EXPORT UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, const UA_QualifiedName browseName, const UA_MethodAttributes attr, UA_MethodCallback method, void *handle, UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments, UA_NodeId *outNewNodeId) { UA_AddNodesResult result; UA_AddNodesResult_init(&result); UA_AddNodesItem item; UA_AddNodesItem_init(&item); result.statusCode = UA_QualifiedName_copy(&browseName, &item.browseName); item.nodeClass = UA_NODECLASS_METHOD; result.statusCode |= UA_NodeId_copy(&parentNodeId, &item.parentNodeId.nodeId); result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId); result.statusCode |= UA_NodeId_copy(&requestedNewNodeId, &item.requestedNewNodeId.nodeId); UA_MethodAttributes attrCopy; result.statusCode |= UA_MethodAttributes_copy(&attr, &attrCopy); if(result.statusCode != UA_STATUSCODE_GOOD) { UA_AddNodesItem_deleteMembers(&item); UA_MethodAttributes_deleteMembers(&attrCopy); return result.statusCode; } UA_MethodNode *node = UA_MethodNode_new(); if(!node) { result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY; UA_AddNodesItem_deleteMembers(&item); UA_MethodAttributes_deleteMembers(&attrCopy); return result.statusCode; } copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy); node->executable = attrCopy.executable; node->userExecutable = attrCopy.executable; node->attachedMethod = method; node->methodHandle = handle; UA_AddNodesItem_deleteMembers(&item); UA_MethodAttributes_deleteMembers(&attrCopy); UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId, &item.referenceTypeId, &result); if(result.statusCode != UA_STATUSCODE_GOOD) { UA_MethodNode_delete(node); return result.statusCode; } UA_ExpandedNodeId parent; UA_ExpandedNodeId_init(&parent); parent.nodeId = result.addedNodeId; /* create InputArguments */ UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new(); inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex; inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments"); inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments"); inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments"); inputArgumentsVariableNode->valueRank = 1; UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments, inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); UA_AddNodesResult inputAddRes; const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode, &parent.nodeId, &hasproperty, &inputAddRes); // todo: check if adding succeeded UA_AddNodesResult_deleteMembers(&inputAddRes); /* create OutputArguments */ UA_VariableNode *outputArgumentsVariableNode = UA_VariableNode_new(); outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex; outputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments"); outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments"); outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments"); outputArgumentsVariableNode->valueRank = 1; UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments, outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); UA_AddNodesResult outputAddRes; UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode, &parent.nodeId, &hasproperty, &outputAddRes); // todo: check if adding succeeded UA_AddNodesResult_deleteMembers(&outputAddRes); if(outNewNodeId) *outNewNodeId = result.addedNodeId; else UA_AddNodesResult_deleteMembers(&result); return result.statusCode; }