UA_StatusCode UA_EXPORT UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, const UA_QualifiedName browseName, const UA_NodeId typeDefinition, const UA_VariableAttributes attr, const UA_DataSource dataSource, 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_VARIABLE; 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); result.statusCode |= UA_NodeId_copy(&typeDefinition, &item.typeDefinition.nodeId); UA_VariableAttributes attrCopy; result.statusCode |= UA_VariableAttributes_copy(&attr, &attrCopy); if(result.statusCode != UA_STATUSCODE_GOOD) { UA_AddNodesItem_deleteMembers(&item); UA_VariableAttributes_deleteMembers(&attrCopy); return result.statusCode; } UA_VariableNode *node = UA_VariableNode_new(); if(!node) { UA_AddNodesItem_deleteMembers(&item); UA_VariableAttributes_deleteMembers(&attrCopy); return UA_STATUSCODE_BADOUTOFMEMORY; } copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy); node->valueSource = UA_VALUESOURCE_DATASOURCE; node->value.dataSource = dataSource; node->accessLevel = attr.accessLevel; node->userAccessLevel = attr.userAccessLevel; node->historizing = attr.historizing; node->minimumSamplingInterval = attr.minimumSamplingInterval; node->valueRank = attr.valueRank; UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId, &item.referenceTypeId, &result); UA_AddNodesItem_deleteMembers(&item); UA_VariableAttributes_deleteMembers(&attrCopy); if(result.statusCode != UA_STATUSCODE_GOOD) UA_VariableNode_delete(node); if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD) *outNewNodeId = result.addedNodeId; else UA_AddNodesResult_deleteMembers(&result); return result.statusCode; }
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; }
void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item, UA_AddNodesResult *result) { if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED || !item->nodeAttributes.content.decoded.type) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } /* create the node */ UA_Node *node; switch(item->nodeClass) { case UA_NODECLASS_OBJECT: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = objectNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_VARIABLE: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = variableNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_OBJECTTYPE: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = objectTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_VARIABLETYPE: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = variableTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_REFERENCETYPE: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = referenceTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_DATATYPE: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = dataTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_VIEW: if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_VIEWATTRIBUTES]) { result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; return; } node = viewNodeFromAttributes(item, item->nodeAttributes.content.decoded.data); break; case UA_NODECLASS_METHOD: case UA_NODECLASS_UNSPECIFIED: default: result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; return; } if(!node) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; 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; } /* 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); }
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, size_t inputArgumentsSize, const UA_Argument* inputArguments, size_t 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_NodeStore_newMethodNode(); 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_RCU_LOCK(); UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId, &item.referenceTypeId, &result); UA_RCU_UNLOCK(); if(result.statusCode != UA_STATUSCODE_GOOD) return result.statusCode; UA_ExpandedNodeId parent; UA_ExpandedNodeId_init(&parent); parent.nodeId = result.addedNodeId; /* create InputArguments */ /* FIXME: The namespace compiler does currently not recognize the interdependancy between methods * and arguments - everything is treated as a standalone node. * In order to allow the compiler to create methods with arguments from an XML, this routine * must be coerced into *not* creating arguments, as these will be added by the compiler as * standalone nodes later. A semantic of inputArgumentsSize < 0 is used to signal this. * * This is not a production feature and should be fixed on the compiler side! (@ichrispa) */ const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode(); 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; UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode, &parent.nodeId, &hasproperty, &inputAddRes); // todo: check if adding succeeded UA_AddNodesResult_deleteMembers(&inputAddRes); /* create OutputArguments */ /* FIXME: See comment in inputArguments */ UA_VariableNode *outputArgumentsVariableNode = UA_NodeStore_newVariableNode(); 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; // don't deleteMember the result else UA_AddNodesResult_deleteMembers(&result); return result.statusCode; }