static UA_StatusCode instantiateObjectNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) { const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId); if(!typenode) return UA_STATUSCODE_BADNODEIDINVALID; if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE) return UA_STATUSCODE_BADNODECLASSINVALID; /* Add all the child nodes */ UA_BrowseDescription browseChildren; UA_BrowseDescription_init(&browseChildren); browseChildren.nodeId = *typeId; browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); browseChildren.includeSubtypes = UA_TRUE; browseChildren.browseDirection = UA_BROWSEDIRECTION_FORWARD; browseChildren.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD; browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS; UA_BrowseResult browseResult; UA_BrowseResult_init(&browseResult); // todo: continuation points if there are too many results Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult); for(size_t i = 0; i < browseResult.referencesSize; i++) { UA_ReferenceDescription *rd = &browseResult.references[i]; if(rd->nodeClass == UA_NODECLASS_METHOD) { /* add a reference to the method in the objecttype */ UA_AddReferencesItem item; UA_AddReferencesItem_init(&item); item.sourceNodeId = *nodeId; item.referenceTypeId = rd->referenceTypeId; item.isForward = UA_TRUE; item.targetNodeId = rd->nodeId; item.targetNodeClass = UA_NODECLASS_METHOD; Service_AddReferences_single(server, session, &item); } else if(rd->nodeClass == UA_NODECLASS_VARIABLE) copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback); else if(rd->nodeClass == UA_NODECLASS_OBJECT) copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback); } /* 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 */ const UA_ObjectLifecycleManagement *olm = &typenode->lifecycleManagement; if(olm->constructor) UA_Server_editNode(server, session, nodeId, (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId)); return UA_STATUSCODE_GOOD; }
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 }
void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request, UA_AddReferencesResponse *response) { if(request->referencesToAddSize <= 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; return; } size_t size = request->referencesToAddSize; if(!(response->results = UA_malloc(sizeof(UA_StatusCode) * size))) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } response->resultsSize = size; #ifdef UA_EXTERNAL_NAMESPACES #ifdef NO_ALLOCA UA_Boolean isExternal[size]; UA_UInt32 indices[size]; #else UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size); UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size); #endif /*NO_ALLOCA */ memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size); for(size_t j = 0; j < server->externalNamespacesSize; j++) { size_t indicesSize = 0; for(size_t i = 0;i < size;i++) { if(request->referencesToAdd[i].sourceNodeId.namespaceIndex != server->externalNamespaces[j].index) continue; isExternal[i] = UA_TRUE; indices[indicesSize] = i; indicesSize++; } if (indicesSize == 0) continue; UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore; ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd, indices, indicesSize, response->results, response->diagnosticInfos); } #endif response->resultsSize = size; for(size_t i = 0; i < response->resultsSize; i++) { #ifdef UA_EXTERNAL_NAMESPACES if(!isExternal[i]) #endif Service_AddReferences_single(server, session, &request->referencesToAdd[i]); } }
static UA_StatusCode 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) return UA_STATUSCODE_BADNODECLASSINVALID; /* get the references to child properties */ UA_BrowseDescription browseChildren; UA_BrowseDescription_init(&browseChildren); browseChildren.nodeId = *typeId; browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); browseChildren.includeSubtypes = UA_TRUE; browseChildren.browseDirection = UA_BROWSEDIRECTION_FORWARD; browseChildren.nodeClassMask = UA_NODECLASS_VARIABLE; browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS; UA_BrowseResult browseResult; UA_BrowseResult_init(&browseResult); // todo: continuation points if there are too many results Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult); /* add the child properties */ for(size_t i = 0; i < browseResult.referencesSize; i++) { UA_ReferenceDescription *rd = &browseResult.references[i]; copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId); } /* 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; }
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; return; } const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId); if(!parent) { result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID; return; } const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId); if(!referenceType) { result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; return; } if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) { result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; return; } if(referenceType->isAbstract == UA_TRUE) { result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED; return; } // todo: test if the referencetype is hierarchical // todo: namespace index is assumed to be valid UA_MT_CONST UA_Node *managed = NULL; UA_NodeId tempNodeid = node->nodeId; tempNodeid.namespaceIndex = 0; if(UA_NodeId_isNull(&tempNodeid)) { if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; return; } result->addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric } else { if(UA_NodeId_copy(&node->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; return; } if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) { result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS; UA_NodeId_deleteMembers(&result->addedNodeId); return; } } /* Careful. The node is inserted. If the nodestore makes an expand, nodes change their address */ // reference back to the parent UA_AddReferencesItem item; UA_AddReferencesItem_init(&item); item.sourceNodeId = managed->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 }