Przeglądaj źródła

Added serverside Service_deleteNodes and wrote deleteOneWayReferenceWithSession() for addresspace.

ichrispa 9 lat temu
rodzic
commit
49caf89298

+ 2 - 0
examples/client.c

@@ -250,6 +250,8 @@ int main(int argc, char *argv[]) {
     void *theCopy;
     UA_Client_getNodeCopy(client, retNodeId, (void*) &theCopy);
     
+    UA_Client_deleteNode(client, UA_NODEID_NUMERIC(1,62541));
+    
     UA_Client_disconnect(client);
     UA_Client_delete(client);
     return UA_STATUSCODE_GOOD;

+ 4 - 0
include/ua_client.h

@@ -60,6 +60,10 @@ UA_DeleteReferencesResponse UA_EXPORT
 
 
 /* Client-Side Macro/Procy functions */
+
+UA_StatusCode UA_EXPORT
+UA_Client_deleteNode(UA_Client *client, UA_NodeId nodeId);
+
 #ifdef ENABLE_METHODCALLS
 UA_CallResponse UA_EXPORT UA_Client_call(UA_Client *client, UA_CallRequest *request);
 UA_StatusCode UA_EXPORT UA_Client_CallServerMethod(UA_Client *client, UA_NodeId objectNodeId, UA_NodeId methodNodeId,

+ 22 - 0
src/client/ua_client.c

@@ -993,6 +993,28 @@ UA_StatusCode UA_Client_CallServerMethod(UA_Client *client, UA_NodeId objectNode
 }
 #endif
 
+/* Delete Node */
+UA_StatusCode UA_Client_deleteNode(UA_Client *client, UA_NodeId nodeId) {
+  UA_DeleteNodesRequest *drq = UA_DeleteNodesRequest_new();
+  UA_DeleteNodesResponse drs;
+  UA_StatusCode retval = UA_STATUSCODE_GOOD;
+  
+  drq->nodesToDeleteSize = 1;
+  drq->nodesToDelete = (UA_DeleteNodesItem *) UA_malloc(sizeof(UA_DeleteNodesItem));
+  drq->nodesToDelete[0].deleteTargetReferences = UA_TRUE;
+  UA_NodeId_copy(&nodeId, &drq->nodesToDelete[0].nodeId);
+  drs = UA_Client_deleteNodes(client, drq);
+  
+  if (drs.responseHeader.serviceResult != UA_STATUSCODE_GOOD || drs.resultsSize < 1)
+    return drs.responseHeader.serviceResult;
+  
+  retval = drs.results[0];
+    
+  UA_DeleteNodesRequest_delete(drq);
+  UA_DeleteNodesResponse_deleteMembers(&drs);
+  return retval;
+}
+
 #define ADDNODES_COPYDEFAULTATTRIBUTES(REQUEST,ATTRIBUTES) do {                           \
     ATTRIBUTES.specifiedAttributes = 0;                                                   \
     if(! UA_LocalizedText_copy(&description, &(ATTRIBUTES.description)))                  \

+ 57 - 0
src/server/ua_server_addressspace.c

@@ -562,6 +562,63 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
 #endif
 }
 
+UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item);
+UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
+  UA_Node *node = UA_NULL;
+  UA_StatusCode retval = UA_Server_getNodeCopy(server, item->sourceNodeId, (void *) &node);
+  if (!node)
+    return retval;
+  
+  // Copy all that do not target the targetNode in a new array
+  UA_ReferenceNode *newRefs = (UA_ReferenceNode*) UA_malloc(sizeof(UA_ReferenceNode) * node->referencesSize);
+  UA_UInt32 newRefCount = 0;
+  for(int refn = 0; refn < node->referencesSize; refn++) {
+    // Completely different target node:
+    if (!UA_NodeId_equal(&item->targetNodeId.nodeId, &node->references[refn].targetId.nodeId)) {
+      UA_ReferenceNode_copy(&node->references[refn], &newRefs[newRefCount]);
+      newRefCount++;
+    }
+    else {
+      // Correct target node, wrong referenceType
+      if (!UA_NodeId_equal(&item->referenceTypeId, &node->references[refn].referenceTypeId)) {
+        UA_ReferenceNode_copy(&node->references[refn], &newRefs[newRefCount]);
+        newRefCount++;
+      }
+      else {
+        // Correct target, correct referenceType, wrong direction
+        // FIXME: Check semantics of deleteBidirectional: does it mean we delete any forward or inverse refs 
+        //        in this node (assumed here) OR does it mean we remove Invers refs from target node??
+        if (item->deleteBidirectional == UA_FALSE && (item->isForward != node->references[refn].isInverse)) {
+          UA_ReferenceNode_copy(&node->references[refn], &newRefs[newRefCount]);
+          newRefCount++;
+        }
+        // else... everything matches, don't copy this node into the new reference array. 
+      }
+    }
+  }
+  
+  // Reallocate
+  UA_ReferenceNode *tmp = UA_realloc(newRefs, sizeof(UA_ReferenceNode) * newRefCount);
+  if (!tmp) {
+    if (newRefCount > 0) 
+      UA_free(newRefs); //realloc with zero size is equal to free!
+    UA_Server_deleteNodeCopy(server, (void *) &node);
+    return UA_STATUSCODE_BADOUTOFMEMORY;
+  }
+  newRefs = tmp;
+  
+  // Swap old references in node for new ones, then free old array
+  tmp = node->references;
+  node->referencesSize = newRefCount;
+  node->references = newRefs;
+  if (tmp)
+    UA_free(tmp);
+  
+  const UA_Node *inserted;
+  retval |= UA_NodeStore_replace(server->nodestore, (const UA_Node *) node, node, &inserted);
+  return retval;
+}
+
 /* userland version of addReferenceWithSession */
 UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
                                      const UA_ExpandedNodeId targetId) {

+ 3 - 0
src/server/ua_server_binary.c

@@ -352,6 +352,9 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     case UA_NS0ID_ADDNODESREQUEST:
         INVOKE_SERVICE(AddNodes, UA_TYPES_ADDNODESRESPONSE);
         break;
+    case UA_NS0ID_DELETENODESREQUEST:
+      INVOKE_SERVICE(DeleteNodes, UA_TYPES_DELETENODESRESPONSE);
+      break;
 #endif
     default: {
         if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787)

+ 40 - 2
src/server/ua_services_nodemanagement.c

@@ -237,6 +237,31 @@ static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_Add
     }
 }
 
+UA_StatusCode deleteNode(UA_Server *server, UA_NodeId nodeId, UA_Boolean deleteReferences);
+UA_StatusCode deleteNode(UA_Server *server, UA_NodeId nodeId, UA_Boolean deleteReferences) {
+  const UA_Node *delNode = UA_NodeStore_get(server->nodestore, &nodeId);
+  if (!delNode)
+    return UA_STATUSCODE_BADNODEIDINVALID;
+  
+  // Find and remove all References to this node if so requested.
+  if(deleteReferences == UA_TRUE) {
+    UA_DeleteReferencesItem *delItem = UA_DeleteReferencesItem_new();
+    delItem->deleteBidirectional = UA_TRUE; // WARNING: Current semantics in deleteOneWayReference is 'delete forward or inverse'
+    UA_NodeId_copy(&nodeId, &delItem->targetNodeId.nodeId);
+    
+    for(int i=0; i<delNode->referencesSize; i++) {
+      UA_NodeId_copy(&delNode->references[i].targetId.nodeId, &delItem->sourceNodeId);
+      
+      UA_NodeId_deleteMembers(&delItem->sourceNodeId);
+    }
+    
+    UA_DeleteReferencesItem_delete(delItem);
+  }
+  
+  UA_NodeStore_release(delNode);
+  return UA_NodeStore_remove(server->nodestore, &nodeId);
+}
+
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response) {
     if(request->nodesToAddSize <= 0) {
@@ -340,10 +365,23 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
                          UA_DeleteNodesResponse *response) {
-
+  UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
+  
+  response->resultsSize = request->nodesToDeleteSize;
+  response->results = (UA_StatusCode *) UA_malloc(sizeof(UA_StatusCode) * request->nodesToDeleteSize);
+  
+  UA_DeleteNodesItem *item;
+  for(int i=0; i<request->nodesToDeleteSize; i++) {
+    item = &request->nodesToDelete[i];
+    response->results[i] = deleteNode(server, item->nodeId, item->deleteTargetReferences);
+  }
+  
+  response->responseHeader.serviceResult = retval;
 }
 
 void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
                               UA_DeleteReferencesResponse *response) {
-
+  UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
+  
+  response->responseHeader.serviceResult = retval;
 }