Explorar el Código

Creates/Added UA_Server_addInstanceOf(); clones a hierarchic objectType (including all method, variables, subobjects and variableTypes) and respects inheritance from supertypes.

ichrispa hace 9 años
padre
commit
d0293da90f
Se han modificado 2 ficheros con 315 adiciones y 0 borrados
  1. 11 0
      include/ua_server.h
  2. 304 0
      src/server/ua_server_addressspace.c

+ 11 - 0
include/ua_server.h

@@ -495,6 +495,17 @@ UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, cons
 
 #endif /* external nodestore */
 
+#ifndef _HAVE_UA_INSTANTIONCALLBACK_D
+#define _HAVE_UA_INSTANTIONCALLBACK_D
+typedef UA_StatusCode (*UA_InstantiationCallback)(UA_NodeId objectId, UA_NodeId definitionId, void *handle);
+#endif
+
+UA_StatusCode UA_EXPORT
+UA_Server_addInstanceOf(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
+                        UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId, 
+                        const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask, 
+                        const UA_ExpandedNodeId typeDefinition, UA_InstantiationCallback *callback, UA_NodeId *createdNodeId);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 304 - 0
src/server/ua_server_addressspace.c

@@ -1203,3 +1203,307 @@ UA_StatusCode UA_Server_getAttributeValue(UA_Server *server, UA_NodeId nodeId, U
   
   return retval;
 }
+
+UA_StatusCode UA_Server_appendInstanceOfSupertype(UA_Server *server, UA_NodeId nodeId, UA_NodeId appendToNodeId, 
+                                                  UA_InstantiationCallback *callback);
+UA_StatusCode UA_Server_appendInstanceOfSupertype(UA_Server *server, UA_NodeId nodeId, UA_NodeId appendToNodeId, 
+                                                  UA_InstantiationCallback *callback)  {
+  UA_StatusCode retval = UA_STATUSCODE_GOOD;
+  UA_Int32 inheritedFromIdsSize = 0;
+  UA_NodeId *inheritedFromIds = NULL;
+  
+  UA_Node *typeDefNode;
+  UA_Server_getNodeCopy(server, nodeId, (void *) &typeDefNode);
+  if (typeDefNode == NULL) {
+    return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+  }
+  if (!typeDefNode->nodeClass == UA_NODECLASS_OBJECTTYPE) {
+    UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
+    return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+  }
+  
+  // These refs will be examined later. 
+  // FIXME: Create these arrays dynamically to include any subtypes as well
+  UA_Int32 subtypeRefsSize = 1;
+  UA_NodeId subtypeRefs[] = { UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)};
+  UA_Int32 componentRefsSize = 2;
+  UA_NodeId componentRefs[] = { UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY)};
+  
+  UA_ReferenceNode ref;
+  UA_Boolean refTypeValid;
+  UA_NodeClass *refClass;
+  UA_Node      *nodeClone;
+  UA_ExpandedNodeId *objectRootExpanded = UA_ExpandedNodeId_new();
+  UA_NodeId_copy(&appendToNodeId, &objectRootExpanded->nodeId );
+  UA_VariableNode *newVarNode;
+  UA_VariableTypeNode *varTypeNode;
+  for(int i=0; i<typeDefNode->referencesSize; i++) {
+    ref = typeDefNode->references[i];
+    if (ref.isInverse == UA_FALSE)
+      continue;
+    refTypeValid = UA_FALSE;
+    for (int j=0; j<subtypeRefsSize; j++) {
+      if (UA_NodeId_equal(&subtypeRefs[j], &ref.referenceTypeId)) {
+        refTypeValid = UA_TRUE;
+        break;
+      }
+    } // End check isSubtype ref
+    if (!refTypeValid) 
+      continue;
+    
+    // Check if already tried to inherit from this node (there is such a thing as duplicate refs)
+    refTypeValid = UA_TRUE;
+    for (int k=0; k<inheritedFromIdsSize; k++) {
+      if (UA_NodeId_equal(&inheritedFromIds[k], &ref.targetId.nodeId)) {
+        refTypeValid = UA_FALSE;
+        break;
+      }
+    }
+    if (!refTypeValid) 
+      continue;
+    
+    // Go ahead and inherit this nodes variables and methods (not objects!)
+    inheritedFromIdsSize++;
+    inheritedFromIds = UA_realloc(inheritedFromIds, sizeof(UA_NodeId) * inheritedFromIdsSize);
+    UA_NodeId_copy(&ref.targetId.nodeId, &inheritedFromIds[inheritedFromIdsSize-1]);
+    UA_Server_appendInstanceOfSupertype(server, ref.targetId.nodeId, appendToNodeId, callback);
+  } // End check all hassubtype refs
+  inheritedFromIdsSize = 0;
+  UA_free(inheritedFromIds);
+  
+  for(int i=0; i<typeDefNode->referencesSize; i++) {
+    ref = typeDefNode->references[i];
+    if (ref.isInverse)
+      continue;
+    refTypeValid = UA_FALSE;
+    for (int j=0; j<componentRefsSize; j++) {
+      if (UA_NodeId_equal(&componentRefs[j], &ref.referenceTypeId)) {
+        refTypeValid = UA_TRUE;
+        break;
+      }
+    } // End check hasComponent ref
+    if (!refTypeValid) 
+      continue;
+    
+    // What type of node is this?
+    refClass = NULL;
+    UA_Server_getAttributeValue(server, ref.targetId.nodeId, UA_ATTRIBUTEID_NODECLASS, (void **) &refClass);
+    switch (*refClass) {
+      case UA_NODECLASS_VARIABLE: // Just clone the variable node with a new nodeId
+        UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &nodeClone);
+        UA_NodeId_init(&nodeClone->nodeId);
+        nodeClone->nodeId.namespaceIndex = appendToNodeId.namespaceIndex;
+        if (nodeClone != NULL)
+          UA_Server_addNode(server, nodeClone,  *objectRootExpanded, ref.referenceTypeId);
+        break;
+      case UA_NODECLASS_VARIABLETYPE: // Convert from a value protoype to a value, then add it
+        UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &varTypeNode);
+        newVarNode = UA_VariableNode_new();
+        newVarNode->nodeId.namespaceIndex = appendToNodeId.namespaceIndex;
+        UA_QualifiedName_copy(&varTypeNode->browseName, &varTypeNode->browseName);
+        UA_LocalizedText_copy(&varTypeNode->displayName, &varTypeNode->displayName);
+        UA_LocalizedText_copy(&varTypeNode->description, &varTypeNode->description);
+        newVarNode->writeMask = varTypeNode->writeMask;
+        newVarNode->userWriteMask = varTypeNode->userWriteMask;
+        newVarNode->valueRank = varTypeNode->valueRank;
+        
+        newVarNode->valueSource = varTypeNode->valueSource;
+        if (varTypeNode->valueSource == UA_VALUESOURCE_DATASOURCE)
+          newVarNode->value.dataSource = varTypeNode->value.dataSource;
+        else
+          UA_Variant_copy(&varTypeNode->value.variant, &newVarNode->value.variant);
+        
+        UA_Server_addNode(server, (UA_Node *) newVarNode, *objectRootExpanded, ref.referenceTypeId);
+        UA_Server_deleteNodeCopy(server, (void **) &newVarNode);
+        UA_Server_deleteNodeCopy(server, (void **) &varTypeNode);
+        break;
+      case UA_NODECLASS_METHOD: // Link this method (don't clone the node)
+        UA_Server_AddMonodirectionalReference(server, appendToNodeId, ref.targetId, ref.referenceTypeId, UA_TRUE);
+        break;
+      default:
+        printf("We don't care about nodeclass %d\n", *refClass);
+    }
+    UA_NodeClass_delete(refClass);
+  }
+  UA_ExpandedNodeId_delete(objectRootExpanded);
+  UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
+  return retval;
+}
+
+UA_StatusCode UA_Server_addInstanceOf(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
+                        UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId, 
+                        const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask, 
+                        const UA_ExpandedNodeId typeDefinition, UA_InstantiationCallback *callback, UA_NodeId *createdNodeId) 
+{
+  UA_StatusCode retval = UA_STATUSCODE_GOOD;
+  
+  UA_Int32 inheritedFromIdsSize = 0;
+  UA_NodeId *inheritedFromIds = NULL;
+  
+  UA_Node *typeDefNode;
+  UA_Server_getNodeCopy(server, typeDefinition.nodeId, (void *) &typeDefNode);
+  
+  if (typeDefNode == NULL) {
+    return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+  }
+  if (!typeDefNode->nodeClass == UA_NODECLASS_OBJECTTYPE) {
+    UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
+    return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+  }
+  
+  // Create the object root as specified by the user
+  UA_NodeId objectRoot;
+  retval |= UA_Server_addObjectNode(server, nodeId, browseName, displayName, description, 
+                          parentNodeId, referenceTypeId, userWriteMask, writeMask,
+                          typeDefinition, &objectRoot
+  );
+  if (retval)
+    return retval;
+  
+  // These refs will be examined later. 
+  // FIXME: Create these arrays dynamically to include any subtypes as well
+  UA_Int32 subtypeRefsSize = 1;
+  UA_NodeId subtypeRefs[] = { UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)};
+  UA_Int32 componentRefsSize = 2;
+  UA_NodeId componentRefs[] = { UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY)};
+  UA_Int32 typedefRefsSize = 1;
+  UA_NodeId typedefRefs[] = { UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION)};
+  
+  UA_ReferenceNode ref;
+  UA_Boolean refTypeValid;
+  UA_NodeClass *refClass;
+  UA_Node      *nodeClone;
+  UA_ExpandedNodeId *objectRootExpanded = UA_ExpandedNodeId_new();
+  UA_VariableNode *newVarNode;
+  UA_VariableTypeNode *varTypeNode;
+  UA_NodeId_copy(&objectRoot, &objectRootExpanded->nodeId );
+  
+  // (1) If this node is a subtype of any other node, create its things first
+  for(int i=0; i<typeDefNode->referencesSize; i++) {
+    ref = typeDefNode->references[i];
+    if (ref.isInverse == UA_FALSE)
+      continue;
+    refTypeValid = UA_FALSE;
+    for (int j=0; j<subtypeRefsSize; j++) {
+      if (UA_NodeId_equal(&subtypeRefs[j], &ref.referenceTypeId)) {
+        refTypeValid = UA_TRUE;
+        break;
+      }
+    } // End check isSubtype ref
+    if (!refTypeValid) 
+      continue;
+    
+    // Check if already tried to inherit from this node (there is such a thing as duplicate refs)
+    refTypeValid = UA_TRUE;
+    for (int k=0; k<inheritedFromIdsSize; k++) {
+      if (UA_NodeId_equal(&inheritedFromIds[k], &ref.targetId.nodeId)) {
+        refTypeValid = UA_FALSE;
+        break;
+      }
+    }
+    if (!refTypeValid) 
+      continue;
+    
+    // Go ahead and inherit this nodes variables and methods (not objects!)
+    inheritedFromIdsSize++;
+    inheritedFromIds = UA_realloc(inheritedFromIds, sizeof(UA_NodeId) * inheritedFromIdsSize);
+    UA_NodeId_copy(&ref.targetId.nodeId, &inheritedFromIds[inheritedFromIdsSize-1]);
+    UA_Server_appendInstanceOfSupertype(server, ref.targetId.nodeId, objectRoot, callback);
+  } // End check all hassubtype refs
+  inheritedFromIdsSize = 0;
+  UA_free(inheritedFromIds); 
+  
+  // (2) For each object or variable referenced with hasComponent or hasProperty, create a new node of that
+  //     type for this objectRoot
+  for(int i=0; i<typeDefNode->referencesSize; i++) {
+    ref = typeDefNode->references[i];
+    if (ref.isInverse)
+      continue;
+    refTypeValid = UA_FALSE;
+    for (int j=0; j<componentRefsSize; j++) {
+      if (UA_NodeId_equal(&componentRefs[j], &ref.referenceTypeId)) {
+        refTypeValid = UA_TRUE;
+        break;
+      }
+    } // End check hasComponent ref
+    if (!refTypeValid) 
+      continue;
+    
+    // What type of node is this?
+    refClass = NULL;
+    UA_Server_getAttributeValue(server, ref.targetId.nodeId, UA_ATTRIBUTEID_NODECLASS, (void **) &refClass);
+    switch (*refClass) {
+      case UA_NODECLASS_VARIABLE: // Just clone the variable node with a new nodeId
+        UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &nodeClone);
+        UA_NodeId_init(&nodeClone->nodeId);
+        nodeClone->nodeId.namespaceIndex = objectRoot.namespaceIndex;
+        if (nodeClone != NULL)
+          UA_Server_addNode(server, nodeClone,  *objectRootExpanded, ref.referenceTypeId);
+        break;
+      case UA_NODECLASS_VARIABLETYPE: // Convert from a value protoype to a value, then add it
+        UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &varTypeNode);
+        newVarNode = UA_VariableNode_new();
+        newVarNode->nodeId.namespaceIndex = objectRoot.namespaceIndex;
+        UA_QualifiedName_copy(&varTypeNode->browseName, &varTypeNode->browseName);
+        UA_LocalizedText_copy(&varTypeNode->displayName, &varTypeNode->displayName);
+        UA_LocalizedText_copy(&varTypeNode->description, &varTypeNode->description);
+        newVarNode->writeMask = varTypeNode->writeMask;
+        newVarNode->userWriteMask = varTypeNode->userWriteMask;
+        newVarNode->valueRank = varTypeNode->valueRank;
+        
+        newVarNode->valueSource = varTypeNode->valueSource;
+        if (varTypeNode->valueSource == UA_VALUESOURCE_DATASOURCE)
+          newVarNode->value.dataSource = varTypeNode->value.dataSource;
+        else
+          UA_Variant_copy(&varTypeNode->value.variant, &newVarNode->value.variant);
+        
+        UA_Server_addNode(server, (UA_Node *) newVarNode, *objectRootExpanded, ref.referenceTypeId);
+        UA_Server_deleteNodeCopy(server, (void **) &newVarNode);
+        UA_Server_deleteNodeCopy(server, (void **) &varTypeNode);
+        break;
+      case UA_NODECLASS_OBJECT: // An object may have it's own inheritance or child nodes
+        UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &nodeClone);
+        if (nodeClone == UA_NULL)
+          break; // switch
+          
+        // Retrieve this nodes type definition
+        UA_ExpandedNodeId_init(objectRootExpanded); // Slight misuse of an unsused ExpandedNodeId to encode the typeDefinition
+        for(int k=0; k<nodeClone->referencesSize; k++) {
+          refTypeValid = UA_FALSE;
+          for (int j=0; j<typedefRefsSize; j++) {
+            if (UA_NodeId_equal(&typedefRefs[j], &nodeClone->references[k].referenceTypeId)) {
+              refTypeValid = UA_TRUE;
+              UA_ExpandedNodeId_copy(&nodeClone->references[k].targetId, objectRootExpanded);
+              break;
+            }
+          } // End check isTypedef ref
+          if (!refTypeValid) 
+            continue;
+        } // End iterate over nodeClone refs
+        
+        if (!refTypeValid) // This may be plain wrong, but since got this far...
+          objectRootExpanded->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
+        // ... we might as well keep going
+        
+        UA_Server_addInstanceOf(server, UA_NODEID_NUMERIC(objectRoot.namespaceIndex, 0), nodeClone->browseName,
+                                nodeClone->displayName, nodeClone->description, objectRoot, 
+                                ref.referenceTypeId,nodeClone->userWriteMask, nodeClone->writeMask, 
+                                *objectRootExpanded, callback, NULL
+        );
+        UA_Server_deleteNodeCopy(server, (void **) &nodeClone);
+        UA_ExpandedNodeId_deleteMembers(objectRootExpanded); // since we only borrowed this, reset it
+        UA_NodeId_copy(&objectRoot, &objectRootExpanded->nodeId );
+        break;
+      case UA_NODECLASS_METHOD: // Link this method (don't clone the node)
+        UA_Server_AddMonodirectionalReference(server, objectRoot, ref.targetId, ref.referenceTypeId, UA_TRUE);
+        break;
+      default:
+        printf("We don't care about nodeclass %d\n", *refClass);
+    }
+    UA_NodeClass_delete(refClass);
+  }
+
+  UA_ExpandedNodeId_delete(objectRootExpanded);
+  UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
+  return retval;
+}