Bladeren bron

Reimplemented instantiation callback (required for #503).

ichrispa 9 jaren geleden
bovenliggende
commit
a0ad0e6ea0

+ 0 - 1
CMakeLists.txt

@@ -131,7 +131,6 @@ option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType str
 mark_as_advanced(UA_ENABLE_TYPENAMES)
 
 option(UA_ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition" OFF)
-mark_as_advanced(UA_ENABLE_GENERATE_NAMESPACE0)
 
 option(UA_ENABLE_EMBEDDED_LIBC "Target has no libc, use internal definitions" OFF)
 mark_as_advanced(UA_ENABLE_EMBEDDED_LIBC)

+ 18 - 8
examples/server.c

@@ -200,6 +200,12 @@ nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, voi
     return UA_STATUSCODE_GOOD;
 }
 
+static UA_StatusCode
+instantiationHandle(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
+  printf("Instantiated Node ns=%d; id=%d from ns=%d; id=%d\n", newNodeId.namespaceIndex, newNodeId.identifier.numeric, templateId.namespaceIndex, templateId.identifier.numeric);
+  return UA_STATUSCODE_GOOD;
+}
+
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 #ifdef UA_ENABLE_MULTITHREADING
@@ -288,8 +294,12 @@ int main(int argc, char** argv) {
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    /* Instantiation Callback can be used when a typeDefinition creates new nodes under this added one.
+     * The method will be called for each created node.
+     */
+    UA_InstantiationCallback theAnswerCallback = {.method=instantiationHandle, .handle=(void*) server};
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                              myIntegerName, UA_NODEID_NULL, myVar, NULL);
+                              myIntegerName, UA_NODEID_NULL, myVar, &theAnswerCallback, NULL);
     UA_Variant_deleteMembers(&myVar.value);
 
     /**************/
@@ -304,7 +314,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 #define SCALARID 50001
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
@@ -312,7 +322,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Scalar"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 #define ARRAYID 50002
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
@@ -320,14 +330,14 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Array"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 #define MATRIXID 50003
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
     UA_UInt32 id = 51000; // running id in namespace 0
     for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) {
@@ -347,7 +357,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, SCALARID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an array node for every built-in type */
@@ -356,7 +366,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an matrix node for every built-in type */
@@ -371,7 +381,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, MATRIXID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
     }
 

+ 1 - 1
examples/server_variable.c

@@ -56,7 +56,7 @@ int main(int argc, char** argv) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, attr, NULL);
+                              UA_NODEID_NULL, attr, NULL, NULL);
 
     UA_ValueCallback callback = {(void*)7, onRead, onWrite};
     UA_Server_setVariableNode_valueCallback(server, myIntegerNodeId, callback);

+ 21 - 15
include/ua_server.h

@@ -240,6 +240,11 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
 /* Node Management */
 /*******************/
 
+typedef struct UA_InstantiationCallback_s {
+  UA_StatusCode (*method)(UA_NodeId objectId, UA_NodeId definitionId, void *handle);
+  void *handle;
+} UA_InstantiationCallback;
+
 UA_StatusCode UA_EXPORT
 UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
                        const UA_ExpandedNodeId targetId, UA_Boolean isForward);
@@ -257,70 +262,71 @@ UA_StatusCode UA_EXPORT
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                    const UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
+                    const UA_NodeAttributes *attr, const UA_DataType *attributeType, 
+                    UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId);
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                          const UA_VariableAttributes attr, UA_NodeId *outNewNodeId) {
+                          const UA_VariableAttributes attr, UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                               const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
-                              UA_NodeId *outNewNodeId) {
+                              UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
+                        const UA_ObjectAttributes attr, UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                             const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                             const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
-                            UA_NodeId *outNewNodeId) {
+                            UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                       const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                       const UA_QualifiedName browseName, const UA_ViewAttributes attr,
-                      UA_NodeId *outNewNodeId) {
+                      UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
-                               UA_NodeId *outNewNodeId) {
+                               UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
-                          UA_NodeId *outNewNodeId) {
+                          UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 UA_StatusCode UA_EXPORT
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,

+ 3 - 2
src/server/ua_server.c

@@ -222,7 +222,8 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
-                    const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
+                    const UA_DataType *attributeType, 
+                    UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
     item.parentNodeId.nodeId = parentNodeId;
@@ -236,7 +237,7 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     UA_RCU_LOCK();
-    Service_AddNodes_single(server, &adminSession, &item, &result);
+    Service_AddNodes_single(server, &adminSession, &item, &result, instantiationCallback);
     UA_RCU_UNLOCK();
 
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)

+ 1 - 1
src/server/ua_services.h

@@ -116,7 +116,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session,
                       const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result);
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback);
 
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session,

+ 35 - 22
src/server/ua_services_nodemanagement.c

@@ -80,16 +80,18 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session,
-                        const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                        const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                        UA_InstantiationCallback *instantiationCallback);
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback);
 
 /* copy an existing variable under the given parent. then instantiate the
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                     const UA_NodeId *referenceType, const UA_NodeId *parent) {
+                     const UA_NodeId *referenceType, const UA_NodeId *parent, UA_InstantiationCallback *instantiationCallback) {
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -127,7 +129,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     // add the new variable
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
 
@@ -139,9 +141,12 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
-        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateVariableNode(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;
 }
@@ -150,7 +155,8 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
    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) {
+                   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;
@@ -180,7 +186,7 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     // add the new object
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
 
@@ -192,9 +198,12 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
         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);
+        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;
 }
@@ -209,13 +218,14 @@ setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* n
 
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback) {   
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(type->nodeClass != UA_NODECLASS_OBJECTTYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     /* Add all the child nodes */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -244,9 +254,9 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
             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);
+          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);
+          copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
 
     /* add a hastypedefinition reference */
@@ -269,13 +279,13 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                        const UA_NodeId *typeId) {
+                        const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
     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);
@@ -294,7 +304,7 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     /* 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);
+        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
 
     /* add a hastypedefinition reference */
@@ -434,7 +444,7 @@ dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttribu
 }
 
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result) {
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback) {
     if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
        !item->nodeAttributes.content.decoded.type) {
         result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -512,15 +522,18 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_Ad
         UA_Node_deleteAnyNodeClass(node);
         return;
     }
-
+    
     /* instantiate if it has a type */
     if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
+        if (instantiationCallback != NULL)
+          instantiationCallback->method(result->addedNodeId, item->typeDefinition.nodeId, instantiationCallback->handle); 
+        
         if(item->nodeClass == UA_NODECLASS_OBJECT)
             result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
-                                                       &item->typeDefinition.nodeId);
+                                                       &item->typeDefinition.nodeId, instantiationCallback);
         else if(item->nodeClass == UA_NODECLASS_VARIABLE)
             result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
-                                                         &item->typeDefinition.nodeId);
+                                                         &item->typeDefinition.nodeId, instantiationCallback);
     }
 
     /* if instantiation failed, remove the node */
@@ -574,7 +587,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
-            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i]);
+            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i], NULL);
     }
 }
 

+ 4 - 4
tests/check_services_attributes.c

@@ -34,7 +34,7 @@ static UA_Server* makeTestSequence(void) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 	
     /* DataSource VariableNode */
     UA_VariableAttributes_init(&vattr);
@@ -63,7 +63,7 @@ static UA_Server* makeTestSequence(void) {
     parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 
     /* ObjectNode */
     UA_ObjectAttributes obj_attr;
@@ -75,7 +75,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Demo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
-                            obj_attr, NULL);
+                            obj_attr, NULL, NULL);
 
     /* ViewNode */
     UA_ViewAttributes view_attr;
@@ -85,7 +85,7 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL);
+                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL, NULL);
 
 #ifdef UA_ENABLE_METHODCALLS
 	/* MethodNode */

+ 32 - 3
tests/check_services_nodemanagement.c

@@ -17,6 +17,11 @@
 #include <urcu.h>
 #endif
 
+static UA_StatusCode
+instantiationMethod(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
+  *((UA_Int32 *) handle) += 1;
+  return UA_STATUSCODE_GOOD;
+}
 START_TEST(AddVariableNode) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
@@ -32,11 +37,34 @@ START_TEST(AddVariableNode) {
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                                  myIntegerName, UA_NODEID_NULL, attr, NULL);
+                                                  myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
     UA_Server_delete(server);
 } END_TEST
 
+START_TEST(AddComplexTypeWithInheritance) {
+  UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+  
+  /* add a variable node to the address space */
+  UA_ObjectAttributes attr;
+  UA_ObjectAttributes_init(&attr);
+  attr.description = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
+  attr.displayName = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
+  
+  UA_NodeId myObjectNodeId = UA_NODEID_STRING(1, "the.fake.Server.Struct");
+  UA_QualifiedName myObjectName = UA_QUALIFIEDNAME(1, "the.fake.Server.Struct");
+  UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+  UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+  UA_Int32 handleCalled;
+  UA_InstantiationCallback iCallback = {.method=instantiationMethod, .handle = (void *) &handleCalled};
+    
+  UA_StatusCode res = UA_Server_addObjectNode(server, myObjectNodeId, parentNodeId, parentReferenceNodeId,
+                                                myObjectName, UA_NODEID_NUMERIC(0, 2004), attr, &iCallback, NULL);
+  ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
+  ck_assert_int_gt(handleCalled, 0); // Should be 58, but may depend on NS0 XML detail
+  UA_Server_delete(server);
+} END_TEST
+
 START_TEST(AddNodeTwiceGivesError) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
@@ -52,10 +80,10 @@ START_TEST(AddNodeTwiceGivesError) {
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                                  myIntegerName, UA_NODEID_NULL, attr, NULL);
+                                                  myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
     res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                    myIntegerName, UA_NODEID_NULL, attr, NULL);
+                                    myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_BADNODEIDEXISTS);
     UA_Server_delete(server);
 } END_TEST
@@ -65,6 +93,7 @@ static Suite * testSuite_services_nodemanagement(void) {
 
 	TCase *tc_addnodes = tcase_create("addnodes");
 	tcase_add_test(tc_addnodes, AddVariableNode);
+        tcase_add_test(tc_addnodes, AddComplexTypeWithInheritance);
 	tcase_add_test(tc_addnodes, AddNodeTwiceGivesError);
 
 	suite_add_tcase(s, tc_addnodes);

+ 1 - 1
tools/pyUANamespace/open62541_MacroHelper.py

@@ -137,7 +137,7 @@ class open62541_MacroHelper():
       code.append("       , typeDefinition")
     
     if nodetype != "Method":
-      code.append("       , attr, NULL);")
+      code.append("       , attr, NULL, NULL);")
     else:
       # FIXME:  Semantic of inputArgumentSize = -1 is used to signal the suppression of argument creation.
       #         This should be replaced with a properly generated struct for the arguments.