void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, UA_AddNodesResult *result) { if(node->nodeId.namespaceIndex >= server->namespacesSize) { result->statusCode = UA_STATUSCODE_BADNODEIDINVALID; UA_NodeStore_deleteNode(node); return; } const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId); if(!parent) { result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID; UA_NodeStore_deleteNode(node); return; } const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId); if(!referenceType) { result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; UA_NodeStore_deleteNode(node); return; } if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) { result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; UA_NodeStore_deleteNode(node); return; } if(referenceType->isAbstract == UA_TRUE) { result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED; UA_NodeStore_deleteNode(node); return; } // todo: test if the referencetype is hierarchical // todo: namespace index is assumed to be valid result->statusCode = UA_NodeStore_insert(server->nodestore, node); if(result->statusCode == UA_STATUSCODE_GOOD) result->statusCode = UA_NodeId_copy(&node->nodeId, &result->addedNodeId); else return; // reference back to the parent UA_AddReferencesItem item; UA_AddReferencesItem_init(&item); item.sourceNodeId = node->nodeId; item.referenceTypeId = *referenceTypeId; item.isForward = UA_FALSE; item.targetNodeId.nodeId = *parentNodeId; Service_AddReferences_single(server, session, &item); // todo: error handling. remove new node from nodestore }
UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, UA_EditNodeCallback callback, const void *data) { UA_StatusCode retval; do { #ifndef UA_ENABLE_MULTITHREADING const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId); if(!node) return UA_STATUSCODE_BADNODEIDUNKNOWN; UA_Node *editNode = (UA_Node*)(uintptr_t)node; // dirty cast. use only here. retval = callback(server, session, editNode, data); return retval; #else UA_Node *copy = UA_NodeStore_getCopy(server->nodestore, nodeId); if(!copy) return UA_STATUSCODE_BADOUTOFMEMORY; retval = callback(server, session, copy, data); if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode(copy); return retval; } retval = UA_NodeStore_replace(server->nodestore, copy); #endif } while(retval != UA_STATUSCODE_GOOD); return UA_STATUSCODE_GOOD; }
static UA_Node * dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) { UA_DataTypeNode *dtnode = UA_NodeStore_newDataTypeNode(); if(!dtnode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr); dtnode->isAbstract = attr->isAbstract; if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode((UA_Node*)dtnode); return NULL; } return (UA_Node*)dtnode; }
static UA_Node * objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) { UA_ObjectNode *onode = UA_NodeStore_newObjectNode(); if(!onode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr); onode->eventNotifier = attr->eventNotifier; if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode((UA_Node*)onode); return NULL; } return (UA_Node*)onode; }
static UA_Node * viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) { UA_ViewNode *vnode = UA_NodeStore_newViewNode(); if(!vnode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr); vnode->containsNoLoops = attr->containsNoLoops; vnode->eventNotifier = attr->eventNotifier; if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode((UA_Node*)vnode); return NULL; } return (UA_Node*)vnode; }
static UA_Node * referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) { UA_ReferenceTypeNode *rtnode = UA_NodeStore_newReferenceTypeNode(); if(!rtnode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr); rtnode->isAbstract = attr->isAbstract; rtnode->symmetric = attr->symmetric; retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName); if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode((UA_Node*)rtnode); return NULL; } return (UA_Node*)rtnode; }
static UA_Node * variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) { UA_VariableTypeNode *vtnode = UA_NodeStore_newVariableTypeNode(); if(!vtnode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)vtnode, item, (const UA_NodeAttributes*)attr); UA_Variant_copy(&attr->value, &vtnode->value.variant.value); // datatype is taken from the value vtnode->valueRank = attr->valueRank; // array dimensions are taken from the value vtnode->isAbstract = attr->isAbstract; if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode((UA_Node*)vtnode); return NULL; } return (UA_Node*)vtnode; }
static UA_Node * variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) { UA_VariableNode *vnode = UA_NodeStore_newVariableNode(); if(!vnode) return NULL; UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr); // todo: test if the type / valueRank / value attributes are consistent vnode->accessLevel = attr->accessLevel; vnode->userAccessLevel = attr->userAccessLevel; vnode->historizing = attr->historizing; vnode->minimumSamplingInterval = attr->minimumSamplingInterval; vnode->valueRank = attr->valueRank; retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value); if(retval != UA_STATUSCODE_GOOD) { UA_NodeStore_deleteNode((UA_Node*)vnode); return NULL; } return (UA_Node*)vnode; }