/* copy an existing object under the given parent. then instantiate the variable for all hastypedefinitions of the original version. */ static UA_StatusCode copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable, const UA_NodeId *referenceType, const UA_NodeId *parent, UA_InstantiationCallback *instantiationCallback) { const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable); if(!node) return UA_STATUSCODE_BADNODEIDINVALID; if(node->nodeClass != UA_NODECLASS_OBJECT) return UA_STATUSCODE_BADNODECLASSINVALID; // copy the variable attributes UA_ObjectAttributes attr; UA_ObjectAttributes_init(&attr); UA_LocalizedText_copy(&node->displayName, &attr.displayName); UA_LocalizedText_copy(&node->description, &attr.description); attr.writeMask = node->writeMask; attr.userWriteMask = node->userWriteMask; attr.eventNotifier = node->eventNotifier; UA_AddNodesItem item; UA_AddNodesItem_init(&item); UA_NodeId_copy(parent, &item.parentNodeId.nodeId); UA_NodeId_copy(referenceType, &item.referenceTypeId); UA_QualifiedName_copy(&node->browseName, &item.browseName); item.nodeClass = UA_NODECLASS_OBJECT; item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]; item.nodeAttributes.content.decoded.data = &attr; // don't add a typedefinition here. // add the new object UA_AddNodesResult res; UA_AddNodesResult_init(&res); Service_AddNodes_single(server, session, &item, &res, instantiationCallback); UA_ObjectAttributes_deleteMembers(&attr); UA_AddNodesItem_deleteMembers(&item); // now instantiate the object for all hastypedefinition references for(size_t i = 0; i < node->referencesSize; i++) { UA_ReferenceNode *rn = &node->references[i]; if(rn->isInverse) continue; const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef)) continue; instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback); } if (instantiationCallback != NULL) instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle); UA_AddNodesResult_deleteMembers(&res); return UA_STATUSCODE_GOOD; }
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); }