Selaa lähdekoodia

nodeContext pointer for every node

Julius Pfrommer 7 vuotta sitten
vanhempi
commit
95e322df4d

+ 102 - 80
include/ua_server.h

@@ -608,22 +608,81 @@ UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
 #endif
 
 /**
- * Node Management
- * ---------------
+ * Node Lifecycle
+ * --------------
  *
- * Callback Mechanisms
- * ^^^^^^^^^^^^^^^^^^^
- * There are four mechanisms for callbacks from the node-based information model
- * into userspace:
+ * Every node has a context pointer with user-defined data (or NULL). The
+ * user-defined data is assigned before the first constructor is called. The
+ * constructors and destructors can can change (reallocate or free) the context
+ * pointer.
  *
+ * There are two layers of lifecycle management: global and for the specific
+ * node-type (for VariableTypes and ObjectTypes only). The lifecycle is as
+ * follows:
+ *
+ * 1. Global Constructor
+ * 2. Node-Type Constructor (for Variables and Objects)
+ * 3. (Usage-period of the Node)
+ * 4. Node-Type Destructor
+ * 5. Global Destructor
+ *
+ * The constructor callbacks can be set to NULL and are not used in that case.
+ * When the AddNodes service is used over the network, the context pointer is
+ * initially set to NULL.
+ *
+ * If the node-type constructor fails, the global destructor is called before
+ * the node is removed.
+ *
+ * Global Node Lifecycle
+ * ^^^^^^^^^^^^^^^^^^^^^ */
+
+typedef struct {
+    /* Can be NULL. */
+    UA_StatusCode (*constructor)(const UA_NodeId *nodeId, void **nodeContext);
+
+    /* Can be NULL. The global destructor cannot set a new context pointer. The
+     * node memory is freed directly afterwards anyway. */
+    void (*destructor)(const UA_NodeId *nodeId, void *nodeContext);
+} UA_NodeLifecycle;
+
+void UA_EXPORT
+UA_Server_setNodeLifecycle(UA_Server *server, UA_NodeLifecycle lifecycle);
+
+/**
+ * Node Type Lifecycle
+ * ^^^^^^^^^^^^^^^^^^^ */
+
+typedef struct {
+    /* Can be NULL. */
+    UA_StatusCode (*constructor)(const UA_NodeId *typeId, void *typeContext,
+                                 const UA_NodeId *instanceId, void **instanceContext);
+
+    /* Can be NULL. */
+    void (*destructor)(const UA_NodeId *typeId, void *typeContext,
+                       const UA_NodeId *instanceId, void **instanceContext);
+} UA_NodeTypeLifecycle;
+
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
+                               UA_NodeTypeLifecycle lifecycle);
+
+/**
+ * Interacting with the Node Context
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
+
+UA_StatusCode UA_EXPORT
+UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId, void **context);
+
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId, void *context);
+
+/**
+ * Variable Value Storage
+ * ^^^^^^^^^^^^^^^^^^^^^^
  * - Datasources for variable nodes, where the variable content is managed
  *   externally
  * - Value-callbacks for variable nodes, where userspace is notified when a
  *   read/write occurs
- * - Object lifecycle management, where a user-defined constructor and
- *   destructor is added to an object type
- * - Method callbacks, where a user-defined method is exposed in the information
- *   model
  *
  * .. _datasource:
  *
@@ -639,8 +698,6 @@ UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
  * It is expected that the read callback is implemented. The write callback can
  * be set to a null-pointer. */
 typedef struct {
-    void *handle; /* A custom pointer to reuse the same datasource functions for
-                     multiple sources */
     /* Copies the data from the source into the provided value.
      *
      * @param handle An optional pointer to user-defined data for the
@@ -658,7 +715,7 @@ typedef struct {
      * @return Returns a status code for logging. Error codes intended for the
      *         original caller are set in the value. If an error is returned,
      *         then no releasing of the value is done. */
-    UA_StatusCode (*read)(void *handle, const UA_NodeId nodeid,
+    UA_StatusCode (*read)(const UA_NodeId *nodeId, void *nodeContext,
                           UA_Boolean includeSourceTimeStamp,
                           const UA_NumericRange *range, UA_DataValue *value);
 
@@ -671,9 +728,8 @@ typedef struct {
      * @param data The data to be written into the data source
      * @param range An optional data range. If the data source is scalar or does
      *        not support writing of ranges, then an error code is returned.
-     * @return Returns a status code that is returned to the user
-     */
-    UA_StatusCode (*write)(void *handle, const UA_NodeId nodeid,
+     * @return Returns a status code that is returned to the user */
+    UA_StatusCode (*write)(const UA_NodeId *nodeId, void *nodeContext,
                            const UA_Variant *data, const UA_NumericRange *range);
 } UA_DataSource;
 
@@ -689,9 +745,6 @@ UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  * Value Callbacks can be attached to variable and variable type nodes. If
  * not-null, they are called before reading and after writing respectively. */
 typedef struct {
-    /* Pointer to user-provided data for the callback */
-    void *handle;
-
     /* Called before the value attribute is read. It is possible to write into the
      * value attribute during onRead (using the write service). The node is
      * re-opened afterwards so that changes are considered in the following read
@@ -702,7 +755,7 @@ typedef struct {
      * @param data Points to the current node value.
      * @param range Points to the numeric range the client wants to read from
      *        (or NULL). */
-    void (*onRead)(void *handle, const UA_NodeId nodeid,
+    void (*onRead)(const UA_NodeId *nodeid, void *nodeContext, 
                    const UA_Variant *data, const UA_NumericRange *range);
 
     /* Called after writing the value attribute. The node is re-opened after
@@ -713,53 +766,35 @@ typedef struct {
      * @param data Points to the current node value (after writing).
      * @param range Points to the numeric range the client wants to write to (or
      *        NULL). */
-    void (*onWrite)(void *handle, const UA_NodeId nodeid,
+    void (*onWrite)(const UA_NodeId *nodeId, void *nodeContext,
                     const UA_Variant *data, const UA_NumericRange *range);
 } UA_ValueCallback;
 
 UA_StatusCode UA_EXPORT
-UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
+UA_Server_setVariableNode_valueCallback(UA_Server *server,
+                                        const UA_NodeId nodeId,
                                         const UA_ValueCallback callback);
 
-/**
- * .. _object-lifecycle:
- *
- * Object Lifecycle Management Callbacks
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * Lifecycle management adds constructor and destructor callbacks to
- * object types. */
-typedef struct {
-    /* Returns the instance handle that is then attached to the node */
-    void * (*constructor)(const UA_NodeId instance);
-    void (*destructor)(const UA_NodeId instance, void *instanceHandle);
-} UA_ObjectLifecycleManagement;
-
-UA_StatusCode UA_EXPORT
-UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server,
-                                                UA_NodeId nodeId,
-                                                UA_ObjectLifecycleManagement olm);
-
 /**
  * Method Callbacks
  * ~~~~~~~~~~~~~~~~ */
 typedef UA_StatusCode
-(*UA_MethodCallback)(void *methodHandle, const UA_NodeId *objectId,
-                     const UA_NodeId *sessionId, void *sessionHandle,
+(*UA_MethodCallback)(const UA_NodeId *methodId, void *methodContext,
+                     const UA_NodeId *objectId, void *objectContext,
+                     const UA_NodeId *sessionId, void *sessionContext,
                      size_t inputSize, const UA_Variant *input,
                      size_t outputSize, UA_Variant *output);
 
-#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
-UA_Server_setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId,
-                                 UA_MethodCallback method, void *handle);
-#endif
+UA_Server_setMethodNode_callback(UA_Server *server,
+                                 const UA_NodeId methodNodeId,
+                                 UA_MethodCallback methodCallback);
 
 /**
  * .. _addnodes:
  *
  * Node Addition and Deletion
  * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
  * When creating dynamic node instances at runtime, chances are that you will
  * not care about the specific NodeId of the new node, as long as you can
  * reference it later. When passing numeric NodeIds with a numeric identifier 0,
@@ -815,8 +850,7 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId *typeDefinition,
                     const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType,
-                    UA_InstantiationCallback *instantiationCallback,
-                    UA_NodeId *outNewNodeId);
+                    void *nodeContext, UA_NodeId *outNewNodeId);
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
@@ -825,13 +859,12 @@ UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_QualifiedName browseName,
                           const UA_NodeId typeDefinition,
                           const UA_VariableAttributes attr,
-                          UA_InstantiationCallback *instantiationCallback,
-                          UA_NodeId *outNewNodeId) {
+                          void *nodeContext, 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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -842,14 +875,13 @@ UA_Server_addVariableTypeNode(UA_Server *server,
                               const UA_QualifiedName browseName,
                               const UA_NodeId typeDefinition,
                               const UA_VariableTypeAttributes attr,
-                              UA_InstantiationCallback *instantiationCallback,
-                              UA_NodeId *outNewNodeId) {
+                              void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
                                &requestedNewNodeId, &parentNodeId, &referenceTypeId,
                                browseName, &typeDefinition,
                                (const UA_NodeAttributes*)&attr,
                                &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -859,13 +891,12 @@ UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_QualifiedName browseName,
                         const UA_NodeId typeDefinition,
                         const UA_ObjectAttributes attr,
-                        UA_InstantiationCallback *instantiationCallback,
-                        UA_NodeId *outNewNodeId) {
+                        void *nodeContext, 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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -874,13 +905,12 @@ UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeI
                             const UA_NodeId referenceTypeId,
                             const UA_QualifiedName browseName,
                             const UA_ObjectTypeAttributes attr,
-                            UA_InstantiationCallback *instantiationCallback,
-                            UA_NodeId *outNewNodeId) {
+                            void *nodeContext, 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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -889,13 +919,12 @@ UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                       const UA_NodeId referenceTypeId,
                       const UA_QualifiedName browseName,
                       const UA_ViewAttributes attr,
-                      UA_InstantiationCallback *instantiationCallback,
-                      UA_NodeId *outNewNodeId) {
+                      void *nodeContext, 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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -905,14 +934,13 @@ UA_Server_addReferenceTypeNode(UA_Server *server,
                                const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName,
                                const UA_ReferenceTypeAttributes attr,
-                               UA_InstantiationCallback *instantiationCallback,
-                               UA_NodeId *outNewNodeId) {
+                               void *nodeContext, 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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -922,13 +950,12 @@ UA_Server_addDataTypeNode(UA_Server *server,
                           const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName,
                           const UA_DataTypeAttributes attr,
-                          UA_InstantiationCallback *instantiationCallback,
-                          UA_NodeId *outNewNodeId) {
+                          void *nodeContext, 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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 UA_StatusCode UA_EXPORT
@@ -940,22 +967,17 @@ UA_Server_addDataSourceVariableNode(UA_Server *server,
                                     const UA_NodeId typeDefinition,
                                     const UA_VariableAttributes attr,
                                     const UA_DataSource dataSource,
-                                    UA_NodeId *outNewNodeId);
+                                    void *nodeContext, UA_NodeId *outNewNodeId);
 
-#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId,
                         const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName,
-                        const UA_MethodAttributes attr,
-                        UA_MethodCallback method, void *handle,
-                        size_t inputArgumentsSize,
-                        const UA_Argument* inputArguments, 
-                        size_t outputArgumentsSize,
-                        const UA_Argument* outputArguments,
-                        UA_NodeId *outNewNodeId);
-#endif
+                        const UA_MethodAttributes attr, UA_MethodCallback method,
+                        size_t inputArgumentsSize, const UA_Argument* inputArguments, 
+                        size_t outputArgumentsSize, const UA_Argument* outputArguments,
+                        void *nodeContext, UA_NodeId *outNewNodeId);
 
 UA_StatusCode UA_EXPORT
 UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,

+ 11 - 18
src/server/ua_nodes.c

@@ -66,7 +66,6 @@ void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
 static UA_StatusCode
 UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
     dst->eventNotifier = src->eventNotifier;
-    dst->instanceHandle = src->instanceHandle;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -112,15 +111,14 @@ UA_VariableTypeNode_copy(const UA_VariableTypeNode *src,
 static UA_StatusCode
 UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
     dst->executable = src->executable;
-    dst->methodHandle  = src->methodHandle;
-    dst->attachedMethod = src->attachedMethod;
+    dst->method = src->method;
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode
 UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
     dst->isAbstract = src->isAbstract;
-    dst->lifecycleManagement = src->lifecycleManagement;
+    dst->lifecycle = src->lifecycle;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -158,6 +156,8 @@ UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst) {
     retval |= UA_LocalizedText_copy(&src->displayName, &dst->displayName);
     retval |= UA_LocalizedText_copy(&src->description, &dst->description);
     dst->writeMask = src->writeMask;
+    dst->context = src->context;
+    dst->lifecycleState = src->lifecycleState;
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Node_deleteMembersAnyNodeClass(dst);
         return retval;
@@ -198,32 +198,25 @@ UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst) {
     /* Copy unique content of the nodeclass */
     switch(src->nodeClass) {
     case UA_NODECLASS_OBJECT:
-        retval = UA_ObjectNode_copy((const UA_ObjectNode*)src,
-                                    (UA_ObjectNode*)dst);
+        retval = UA_ObjectNode_copy((const UA_ObjectNode*)src, (UA_ObjectNode*)dst);
         break;
     case UA_NODECLASS_VARIABLE:
-        retval = UA_VariableNode_copy((const UA_VariableNode*)src,
-                                      (UA_VariableNode*)dst);
+        retval = UA_VariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst);
         break;
     case UA_NODECLASS_METHOD:
-        retval = UA_MethodNode_copy((const UA_MethodNode*)src,
-                                    (UA_MethodNode*)dst);
+        retval = UA_MethodNode_copy((const UA_MethodNode*)src, (UA_MethodNode*)dst);
         break;
     case UA_NODECLASS_OBJECTTYPE:
-        retval = UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)src,
-                                        (UA_ObjectTypeNode*)dst);
+        retval = UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)src, (UA_ObjectTypeNode*)dst);
         break;
     case UA_NODECLASS_VARIABLETYPE:
-        retval = UA_VariableTypeNode_copy((const UA_VariableTypeNode*)src,
-                                          (UA_VariableTypeNode*)dst);
+        retval = UA_VariableTypeNode_copy((const UA_VariableTypeNode*)src, (UA_VariableTypeNode*)dst);
         break;
     case UA_NODECLASS_REFERENCETYPE:
-        retval = UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)src,
-                                           (UA_ReferenceTypeNode*)dst);
+        retval = UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)src, (UA_ReferenceTypeNode*)dst);
         break;
     case UA_NODECLASS_DATATYPE:
-        retval = UA_DataTypeNode_copy((const UA_DataTypeNode*)src,
-                                      (UA_DataTypeNode*)dst);
+        retval = UA_DataTypeNode_copy((const UA_DataTypeNode*)src, (UA_DataTypeNode*)dst);
         break;
     case UA_NODECLASS_VIEW:
         retval = UA_ViewNode_copy((const UA_ViewNode*)src, (UA_ViewNode*)dst);

+ 18 - 7
src/server/ua_nodes.h

@@ -48,6 +48,7 @@ extern "C" {
  * Internally, open62541 uses ``UA_Node`` in places where the exact node type is
  * not known or not important. The ``nodeClass`` attribute is used to ensure the
  * correctness of casting from ``UA_Node`` to a specific node type. */
+
 /* List of reference targets with the same reference type and direction */
 typedef struct {
     UA_NodeId referenceTypeId;
@@ -56,6 +57,13 @@ typedef struct {
     UA_ExpandedNodeId *targetIds;
 } UA_NodeReferenceKind;
 
+/* Which constructors were run on the node? */
+typedef enum {
+    UA_NODELIFECYCLE_FRESH,
+    UA_NODELIFECYCLE_CONSTRUCTOR_GLOBAL,
+    UA_NODELIFECYCLE_CONSTRUCTOR_NODETYPE
+} UA_NodeLifecycleState;
+
 #define UA_NODE_BASEATTRIBUTES                  \
     UA_NodeId nodeId;                           \
     UA_NodeClass nodeClass;                     \
@@ -64,7 +72,11 @@ typedef struct {
     UA_LocalizedText description;               \
     UA_UInt32 writeMask;                        \
     size_t referencesSize;                      \
-    UA_NodeReferenceKind *references;
+    UA_NodeReferenceKind *references;           \
+                                                \
+    /* Members specific to open62541 */         \
+    void *context;                              \
+    UA_NodeLifecycleState lifecycleState;
 
 typedef struct {
     UA_NODE_BASEATTRIBUTES
@@ -183,6 +195,9 @@ typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_Boolean isAbstract;
+
+    /* Members specific to open62541 */
+    UA_NodeTypeLifecycle lifecycle;
 } UA_VariableTypeNode;
 
 /**
@@ -208,8 +223,7 @@ typedef struct {
     UA_Boolean executable;
 
     /* Members specific to open62541 */
-    void *methodHandle;
-    UA_MethodCallback attachedMethod;
+    UA_MethodCallback method;
 } UA_MethodNode;
 
 /**
@@ -223,9 +237,6 @@ typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Byte eventNotifier;
-
-    /* Members specific to open62541 */
-    void *instanceHandle;
 } UA_ObjectNode;
 
 /**
@@ -242,7 +253,7 @@ typedef struct {
     UA_Boolean isAbstract;
 
     /* Members specific to open62541 */
-    UA_ObjectLifecycleManagement lifecycleManagement;
+    UA_NodeTypeLifecycle lifecycle;
 } UA_ObjectTypeNode;
 
 /**

+ 7 - 3
src/server/ua_server_internal.h

@@ -110,6 +110,9 @@ struct UA_Server {
     /* Address Space */
     UA_NodeStore *nodestore;
 
+    /* Global Node Lifecycle */
+    UA_NodeLifecycle nodeLifecycle;
+
 #ifdef UA_ENABLE_DISCOVERY
     /* Discovery */
     LIST_HEAD(registeredServer_list, registeredServer_list_entry) registeredServers; // doubly-linked list of registered servers
@@ -347,7 +350,7 @@ UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
                          const UA_NodeId typeDefinition,
-                         UA_InstantiationCallback *instantiationCallback);
+                         void *nodeContext);
 
 static UA_INLINE UA_StatusCode
 UA_Server_addReferenceTypeNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
@@ -428,7 +431,7 @@ UA_StatusCode
 UA_Server_addMethodNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_QualifiedName browseName,
                               const UA_MethodAttributes attr, UA_MethodCallback method,
-                              void *handle, UA_NodeId *outNewNodeId);
+                              UA_NodeId *outNewNodeId);
 
 UA_StatusCode
 UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
@@ -437,7 +440,8 @@ UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
                                size_t inputArgumentsSize,
                                const UA_Argument* inputArguments,
                                size_t outputArgumentsSize,
-                               const UA_Argument* outputArguments);
+                               const UA_Argument* outputArguments,
+                               void *nodeContext);
 #endif
 
 /**********************/

+ 17 - 18
src/server/ua_server_ns0.c

@@ -23,7 +23,8 @@ UA_THREAD_LOCAL UA_Session* methodCallSession = NULL;
 /****************/
 
 static UA_StatusCode
-readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+readStatus(const UA_NodeId *nodeid, void *nodeContext,
+           UA_Boolean sourceTimestamp,
            const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
@@ -31,7 +32,7 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
         return UA_STATUSCODE_GOOD;
     }
 
-    UA_Server *server = (UA_Server*)handle;
+    UA_Server *server = (UA_Server*)nodeContext;
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     status->startTime = server->startTime;
     status->currentTime = UA_DateTime_now();
@@ -45,7 +46,7 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
     value->value.arrayDimensionsSize = 0;
     value->value.arrayDimensions = NULL;
     value->hasValue = true;
-    if(sourceTimeStamp) {
+    if(sourceTimestamp) {
         value->hasSourceTimestamp = true;
         value->sourceTimestamp = UA_DateTime_now();
     }
@@ -53,14 +54,15 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
 }
 
 static UA_StatusCode
-readNamespaces(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimestamp,
+readNamespaces(const UA_NodeId *nodeid, void *nodeContext,
+               UA_Boolean sourceTimestamp,
                const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_GOOD;
     }
-    UA_Server *server = (UA_Server*)handle;
+    UA_Server *server = (UA_Server*)nodeContext;
     UA_StatusCode retval;
     retval = UA_Variant_setArrayCopy(&value->value, server->namespaces,
                                      server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
@@ -75,9 +77,9 @@ readNamespaces(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimestamp,
 }
 
 static UA_StatusCode
-writeNamespaces(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-                const UA_NumericRange *range) {
-    UA_Server *server = (UA_Server*)handle;
+writeNamespaces(const UA_NodeId *nodeid, void *nodeContext,
+                const UA_Variant *data, const UA_NumericRange *range) {
+    UA_Server *server = (UA_Server*)nodeContext;
 
     /* Check the data type */
     if(data->type != &UA_TYPES[UA_TYPES_STRING])
@@ -111,7 +113,8 @@ writeNamespaces(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
 }
 
 static UA_StatusCode
-readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+readCurrentTime(const UA_NodeId *nodeid, void *nodeContext,
+                UA_Boolean sourceTimeStamp,
                 const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
@@ -133,7 +136,8 @@ readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp
 
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
 static UA_StatusCode
-readMonitoredItems(void *handle, const UA_NodeId *objectId,
+readMonitoredItems(const UA_NodeId *methodId, void *methodContext,
+                   const UA_NodeId *objectId, void *objectContext,
                    const UA_NodeId *sessionId, void *sessionHandle,
                    size_t inputSize, const UA_Variant *input,
                    size_t outputSize, UA_Variant *output) {
@@ -530,17 +534,13 @@ void UA_Server_createNS0(UA_Server *server) {
     nsarray_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     UA_Server_addVariableNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                                     UA_QUALIFIEDNAME(0, "NamespaceArray"), nsarray_attr, NULL);
-    UA_DataSource nsarray_datasource =  {
-        server, //handle
-        readNamespaces, //read
-        writeNamespaces //write
-    };
+    UA_DataSource nsarray_datasource =  {readNamespaces, writeNamespaces};
     UA_Server_setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                                          nsarray_datasource);
     UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
-                             UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), NULL);
+                             UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), server /* context for datasource*/);
 
     /* Begin ServerCapabilities */
     UA_ObjectAttributes servercap_attr = UA_ObjectAttributes_default;
@@ -744,7 +744,6 @@ void UA_Server_createNS0(UA_Server *server) {
                                   UA_QUALIFIEDNAME(0, "GetMonitoredItems"),
                                   addmethodattributes,
                                   readMonitoredItems, /* callback of the method node */
-                                  NULL, /* handle passed with the callback */
                                   NULL);
 
     /* Add the arguments manually to get the nodeids right */
@@ -778,7 +777,7 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                   0, NULL, 0, NULL);
+                                   0, NULL, 0, NULL, NULL);
 #endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */
 
     /* Finish adding the server object */

+ 7 - 7
src/server/ua_services_attribute.c

@@ -483,8 +483,8 @@ readValueAttributeFromNode(UA_Server *server, const UA_VariableNode *vn,
                            UA_DataValue *v, UA_NumericRange *rangeptr) {
     if(vn->value.data.callback.onRead) {
         UA_RCU_UNLOCK();
-        vn->value.data.callback.onRead(vn->value.data.callback.handle,
-                                       vn->nodeId, &vn->value.data.value.value, rangeptr);
+        vn->value.data.callback.onRead(&vn->nodeId, vn->context,
+                                       &vn->value.data.value.value, rangeptr);
         UA_RCU_LOCK();
 #ifdef UA_ENABLE_MULTITHREADING
         /* Reopen the node to see the changes (multithreading only) */
@@ -508,7 +508,7 @@ readValueAttributeFromDataSource(const UA_VariableNode *vn, UA_DataValue *v,
                                   timestamps == UA_TIMESTAMPSTORETURN_BOTH);
     UA_RCU_UNLOCK();
     UA_StatusCode retval =
-        vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
+        vn->value.dataSource.read(&vn->nodeId, vn->context,
                                   sourceTimeStamp, rangeptr, v);
     UA_RCU_LOCK();
     return retval;
@@ -649,15 +649,15 @@ writeValueAttribute(UA_Server *server, UA_VariableNode *node,
                                    change with the nodestore plugin approach) */
 #endif
             UA_RCU_UNLOCK();
-            writtenNode->value.data.callback.onWrite(writtenNode->value.data.callback.handle,
-                          writtenNode->nodeId, &writtenNode->value.data.value.value, rangeptr);
+            writtenNode->value.data.callback.onWrite(&writtenNode->nodeId, writtenNode->context,
+                                                     &writtenNode->value.data.value.value, rangeptr);
             UA_RCU_LOCK();
         }
     } else {
         if(node->value.dataSource.write) {
             UA_RCU_UNLOCK();
-            retval = node->value.dataSource.write(node->value.dataSource.handle,
-                                      node->nodeId, &editableValue.value, rangeptr);
+            retval = node->value.dataSource.write(&node->nodeId, node->context,
+                                                  &editableValue.value, rangeptr);
             UA_RCU_LOCK();
         } else {
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;

+ 16 - 18
src/server/ua_services_call.c

@@ -63,31 +63,28 @@ static void
 Operation_CallMethod(UA_Server *server, UA_Session *session,
                      const UA_CallMethodRequest *request,
                      UA_CallMethodResult *result) {
-    /* Get/verify the method node */
-    const UA_MethodNode *methodCalled =
-        (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
+    /* Verify the method node */
+    const UA_MethodNode *methodCalled = (const UA_MethodNode*)
+        UA_NodeStore_get(server->nodestore, &request->methodId);
     if(!methodCalled)
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
     else if(methodCalled->nodeClass != UA_NODECLASS_METHOD)
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
-    else if(!methodCalled->attachedMethod)
+    else if(!methodCalled->method)
         result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
-
     if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
 
-    /* Get/verify the object node */
-    const UA_ObjectNode *object =
-        (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, &request->objectId);
-    if(!object) {
+    /* Verify the object node */
+    const UA_ObjectNode *object = (const UA_ObjectNode*)
+        UA_NodeStore_get(server->nodestore, &request->objectId);
+    if(!object)
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
-        return;
-    }
-    if(object->nodeClass != UA_NODECLASS_OBJECT &&
-       object->nodeClass != UA_NODECLASS_OBJECTTYPE) {
+    else if(object->nodeClass != UA_NODECLASS_OBJECT &&
+            object->nodeClass != UA_NODECLASS_OBJECTTYPE)
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
+    if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
-    }
 
     /* Verify access rights */
     UA_Boolean executable = methodCalled->executable;
@@ -160,10 +157,11 @@ Operation_CallMethod(UA_Server *server, UA_Session *session,
     methodCallSession = session;
 #endif
     result->statusCode =
-        methodCalled->attachedMethod(methodCalled->methodHandle, &object->nodeId,
-                                     &session->sessionId, session->sessionHandle,
-                                     request->inputArgumentsSize, request->inputArguments,
-                                     result->outputArgumentsSize, result->outputArguments);
+        methodCalled->method(&methodCalled->nodeId, (void*)(uintptr_t)methodCalled->context,
+                             &object->nodeId, (void*)(uintptr_t)&object->context,
+                             &session->sessionId, session->sessionHandle,
+                             request->inputArgumentsSize, request->inputArguments,
+                             result->outputArgumentsSize, result->outputArguments);
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
     methodCallSession = NULL;
 #endif

+ 160 - 108
src/server/ua_services_nodemanagement.c

@@ -10,16 +10,15 @@
 /************************/
 
 static UA_StatusCode
-copyChildNodes(UA_Server *server, UA_Session *session,
-               const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId,
-               UA_InstantiationCallback *instantiationCallback);
+copyChildNodes(UA_Server *server, UA_Session *session, 
+               const UA_NodeId *sourceNodeId,
+               const UA_NodeId *destinationNodeId);
 
 static UA_StatusCode
 Service_AddNode_finish(UA_Server *server, UA_Session *session,
                        const UA_NodeId *nodeId, const UA_NodeId *parentNodeId,
                        const UA_NodeId *referenceTypeId,
-                       const UA_NodeId *typeDefinition,
-                       UA_InstantiationCallback *instantiationCallback);
+                       const UA_NodeId *typeDefinition, void *nodeContext);
 
 static UA_StatusCode
 deleteNode(UA_Server *server, UA_Session *session,
@@ -323,9 +322,8 @@ isMandatoryChild(UA_Server *server, UA_Session *session, const UA_NodeId *childN
 
 static UA_StatusCode
 copyChildNode(UA_Server *server, UA_Session *session,
-              const UA_NodeId *destinationNodeId,
-              const UA_ReferenceDescription *rd,
-              UA_InstantiationCallback *instantiationCallback) {
+              const UA_NodeId *destinationNodeId, 
+              const UA_ReferenceDescription *rd) {
     UA_NodeId existingChild = UA_NODEID_NULL;
     UA_StatusCode retval =
         instanceFindAggregateByBrowsename(server, session, destinationNodeId,
@@ -337,8 +335,7 @@ copyChildNode(UA_Server *server, UA_Session *session,
     if(!UA_NodeId_isNull(&existingChild)) {
         if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
            rd->nodeClass == UA_NODECLASS_OBJECT)
-            retval = copyChildNodes(server, session, &rd->nodeId.nodeId,
-                                    &existingChild, instantiationCallback);
+            retval = copyChildNodes(server, session, &rd->nodeId.nodeId, &existingChild);
         UA_NodeId_deleteMembers(&existingChild);
         return retval;
     }
@@ -388,18 +385,19 @@ copyChildNode(UA_Server *server, UA_Session *session,
 
         /* Call addnode_finish, this recursively adds members, the type definition and so on */
         if(retval == UA_STATUSCODE_GOOD)
-            retval = Service_AddNode_finish(server, session, &node_copy->nodeId,
-                                            destinationNodeId, &rd->referenceTypeId,
-                                            typeId, instantiationCallback);
+            retval = Service_AddNode_finish(server, session, &node->nodeId, destinationNodeId,
+                                            &rd->referenceTypeId, typeId, NULL);
+
+        /* Clean up */
+        UA_NodeId_deleteMembers(&typeId);
     }
     return retval;
 }
 
 /* Copy any children of Node sourceNodeId to another node destinationNodeId. */
 static UA_StatusCode
-copyChildNodes(UA_Server *server, UA_Session *session,
-               const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId,
-               UA_InstantiationCallback *instantiationCallback) {
+copyChildNodes(UA_Server *server, UA_Session *session, 
+               const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId) {
     /* Browse to get all children of the source */
     UA_BrowseDescription bd;
     UA_BrowseDescription_init(&bd);
@@ -421,17 +419,28 @@ copyChildNodes(UA_Server *server, UA_Session *session,
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(size_t i = 0; i < br.referencesSize; ++i) {
         UA_ReferenceDescription *rd = &br.references[i];
-        retval |= copyChildNode(server, session, destinationNodeId,
-                                rd, instantiationCallback);
+        retval |= copyChildNode(server, session, destinationNodeId, rd);
     }
     UA_BrowseResult_deleteMembers(&br);
     return retval;
 }
 
 static UA_StatusCode
-instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                UA_NodeClass nodeClass, const UA_NodeId *typeId,
-                UA_InstantiationCallback *instantiationCallback) {
+instantiateNode(UA_Server *server, UA_Session *session, UA_Node *node,
+                UA_NodeClass nodeClass, const UA_NodeId *typeId) {
+    /* Call the global constructor */
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(server->nodeLifecycle.constructor) {
+        void *context;
+        UA_Server_getNodeContext(server, node->nodeId, &context);
+        void *oldcontext = context;
+        retval = server->nodeLifecycle.constructor(&node->nodeId, &context);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        UA_Server_setNodeContext(server, node->nodeId, context);
+        node->lifecycleState = UA_NODELIFECYCLE_CONSTRUCTOR_GLOBAL;
+    }
+    
     /* Currently, only variables and objects are instantiated */
     if(nodeClass != UA_NODECLASS_VARIABLE &&
        nodeClass != UA_NODECLASS_OBJECT)
@@ -457,32 +466,18 @@ instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
     /* Get the hierarchy of the type and all its supertypes */
     UA_NodeId *hierarchy = NULL;
     size_t hierarchySize = 0;
-    UA_StatusCode retval = getTypeHierarchy(server->nodestore, typeId,
-                                            &hierarchy, &hierarchySize);
+    retval = getTypeHierarchy(server->nodestore, typeId,
+                              &hierarchy, &hierarchySize);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
     /* Copy members of the type and supertypes */
     for(size_t i = 0; i < hierarchySize; ++i)
-        retval |= copyChildNodes(server, session, &hierarchy[i],
-                                 nodeId, instantiationCallback);
+        retval |= copyChildNodes(server, session, &hierarchy[i], nodeId);
     UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    /* Call the object constructor */
-    if(typenode->nodeClass == UA_NODECLASS_OBJECTTYPE) {
-        const UA_ObjectLifecycleManagement *olm =
-            &((const UA_ObjectTypeNode*)typenode)->lifecycleManagement;
-        if(olm->constructor) {
-            UA_RCU_UNLOCK();
-            UA_Server_editNode(server, session, nodeId,
-                               (UA_EditNodeCallback)setObjectInstanceHandle,
-                               (void*)(uintptr_t)olm->constructor);
-            UA_RCU_LOCK();
-        }
-    }
-
     /* Add a hasType reference */
     UA_AddReferencesItem addref;
     UA_AddReferencesItem_init(&addref);
@@ -490,12 +485,22 @@ instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
     addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
     addref.isForward = true;
     addref.targetNodeId.nodeId = *typeId;
-    addReference(server, session, &addref, &retval);
+    retval = addReference(server, session, &addref);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
 
-    /* Call custom callback */
-    if(retval == UA_STATUSCODE_GOOD && instantiationCallback)
-        instantiationCallback->method(*nodeId, *typeId, instantiationCallback->handle);
-    return retval;
+    /* Call the node type constructor */
+    /* if(typenode->nodeClass == UA_NODECLASS_OBJECTTYPE) { */
+    /*     const UA_ObjectLifecycleManagement *olm = */
+    /*         &((const UA_ObjectTypeNode*)typenode)->lifecycleManagement; */
+    /*     if(olm->constructor) { */
+    /*         UA_RCU_UNLOCK(); */
+    /*         UA_Server_editNode(server, session, nodeId, */
+    /*                            (UA_EditNodeCallback)setObjectInstanceHandle, */
+    /*                            olm->constructor); */
+    /*         UA_RCU_LOCK(); */
+    /*     } */
+    /* } */
 }
 
 /***************************************/
@@ -706,7 +711,7 @@ static UA_StatusCode
 Service_AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                        const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
                        const UA_NodeId *typeDefinition,
-                       UA_InstantiationCallback *instantiationCallback) {
+                       void *nodeContext) {
     /* Get the node */
     const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     if(!node)
@@ -747,8 +752,7 @@ Service_AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *
 
     /* Instantiate node. We need the variable type for type checking (e.g. when
      * writing into attributes) */
-    retval = instantiateNode(server, session, nodeId, node->nodeClass,
-                             typeDefinition, instantiationCallback);
+    retval = instantiateNode(server, session, node, node->nodeClass, typeDefinition);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
                             "AddNodes: Node instantiation failed "
@@ -805,7 +809,7 @@ Service_AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *
 static void
 Service_AddNodes_single(UA_Server *server, UA_Session *session,
                         const UA_AddNodesItem *item, UA_AddNodesResult *result,
-                        UA_InstantiationCallback *instantiationCallback) {
+                        void *nodeContext) {
     /* AddNodes_begin */
     Service_AddNode_begin(server, session, item, result);
     if(result->statusCode != UA_STATUSCODE_GOOD)
@@ -815,7 +819,7 @@ Service_AddNodes_single(UA_Server *server, UA_Session *session,
     result->statusCode =
         Service_AddNode_finish(server, session, &result->addedNodeId,
                                &item->parentNodeId.nodeId, &item->referenceTypeId,
-                               &item->typeDefinition.nodeId, instantiationCallback);
+                               &item->typeDefinition.nodeId, nodeContext);
 
     /* If finishing failed, don't even return a NodeId of the added node */
     if(result->statusCode != UA_STATUSCODE_GOOD)
@@ -857,8 +861,7 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId *typeDefinition,
                     const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType,
-                    UA_InstantiationCallback *instantiationCallback,
-                    UA_NodeId *outNewNodeId) {
+                    void *nodeContext, UA_NodeId *outNewNodeId) {
     /* Create the AddNodesItem */
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
@@ -876,7 +879,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, instantiationCallback);
+    Service_AddNodes_single(server, &adminSession, &item, &result, nodeContext);
     UA_RCU_UNLOCK();
     if(outNewNodeId)
         *outNewNodeId = result.addedNodeId;
@@ -920,11 +923,10 @@ UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
                          const UA_NodeId typeDefinition,
-                         UA_InstantiationCallback *instantiationCallback) {
+                         void *nodeContext) {
     UA_RCU_LOCK();
     UA_StatusCode retval = Service_AddNode_finish(server, &adminSession, &nodeId, &parentNodeId,
-                                                  &referenceTypeId, &typeDefinition,
-                                                  instantiationCallback);
+                                                  &referenceTypeId, &typeDefinition, nodeContext);
     UA_RCU_UNLOCK();
     return retval;
 }
@@ -942,7 +944,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server,
                                     const UA_NodeId typeDefinition,
                                     const UA_VariableAttributes attr,
                                     const UA_DataSource dataSource,
-                                    UA_NodeId *outNewNodeId) {
+                                    void *nodeContext, UA_NodeId *outNewNodeId) {
     UA_NodeId newNodeId;
     UA_Boolean  deleteNodeId = UA_FALSE;
     if(!outNewNodeId) {
@@ -968,10 +970,8 @@ UA_Server_addDataSourceVariableNode(UA_Server *server,
 
 UA_StatusCode
 UA_Server_addMethodNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
-                              const UA_QualifiedName browseName,
-                              const UA_MethodAttributes attr,
-                              UA_MethodCallback method, void *handle,
-                              UA_NodeId *outNewNodeId) {
+                              const UA_QualifiedName browseName, const UA_MethodAttributes attr,
+                              UA_MethodCallback method, UA_NodeId *outNewNodeId) {
     /* Create the node */
     UA_MethodNode *node = (UA_MethodNode*)UA_NodeStore_newNode(UA_NODECLASS_METHOD);
     if(!node)
@@ -979,8 +979,7 @@ UA_Server_addMethodNode_begin(UA_Server *server, const UA_NodeId requestedNewNod
 
     /* Set the node attributes */
     node->executable = attr.executable;
-    node->attachedMethod = method;
-    node->methodHandle = handle;
+    node->method = method;
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
     item.requestedNewNodeId.nodeId = requestedNewNodeId;
@@ -1008,7 +1007,8 @@ UA_StatusCode
 UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                size_t inputArgumentsSize, const UA_Argument* inputArguments,
-                               size_t outputArgumentsSize, const UA_Argument* outputArguments) {
+                               size_t outputArgumentsSize, const UA_Argument* outputArguments,
+                               void *nodeContext) {
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     const UA_NodeId propertytype = UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE);
     const UA_NodeId argsId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
@@ -1090,7 +1090,7 @@ UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
     /* Call finish to add the parent reference */
     UA_RCU_LOCK();
     retval |= Service_AddNode_finish(server, &adminSession, &nodeId, &parentNodeId,
-                                     &referenceTypeId, &UA_NODEID_NULL, NULL);
+                                     &referenceTypeId, &UA_NODEID_NULL, nodeContext);
     UA_RCU_UNLOCK();
 
     if(retval != UA_STATUSCODE_GOOD) {
@@ -1106,10 +1106,10 @@ UA_StatusCode
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
-                        UA_MethodCallback method, void *handle,
-                        size_t inputArgumentsSize, const UA_Argument* inputArguments,
+                        UA_MethodCallback method,
+                        size_t inputArgumentsSize, const UA_Argument* inputArguments, 
                         size_t outputArgumentsSize, const UA_Argument* outputArguments,
-                        UA_NodeId *outNewNodeId) {
+                        void *nodeContext, UA_NodeId *outNewNodeId) {
     UA_NodeId newId;
     if(!outNewNodeId) {
         UA_NodeId_init(&newId);
@@ -1119,7 +1119,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     /* Call begin */
     UA_StatusCode retval =
         UA_Server_addMethodNode_begin(server, requestedNewNodeId, browseName,
-                                      attr, method, handle, outNewNodeId);
+                                      attr, method, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -1127,7 +1127,8 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     retval = UA_Server_addMethodNode_finish(server, *outNewNodeId,
                                             parentNodeId, referenceTypeId,
                                             inputArgumentsSize, inputArguments,
-                                            outputArgumentsSize, outputArguments);
+                                            outputArgumentsSize, outputArguments,
+                                            nodeContext);
 
     if(outNewNodeId == &newId)
         UA_NodeId_deleteMembers(&newId);
@@ -1317,8 +1318,9 @@ deleteNode(UA_Server *server, UA_Session *session,
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-    /* TODO: check if the information model consistency is violated */
+    /* TODO: Check if the information model consistency is violated */
     /* TODO: Check if the node is a mandatory child of an object */
+    // TODO: use the type destructor only when it previously succeeded.
 
     /* Destroy an object before removing it */
     if(node->nodeClass == UA_NODECLASS_OBJECT) {
@@ -1326,11 +1328,17 @@ deleteNode(UA_Server *server, UA_Session *session,
         UA_RCU_LOCK();
         const UA_ObjectTypeNode *typenode =
             getObjectNodeType(server, (const UA_ObjectNode*)node);
-        UA_RCU_UNLOCK();
-        if(typenode && typenode->lifecycleManagement.destructor) {
-            const UA_ObjectNode *on = (const UA_ObjectNode*)node;
-            typenode->lifecycleManagement.destructor(*nodeId, on->instanceHandle);
-        }
+        // todo: writing the new context
+        if(typenode && typenode->lifecycle.destructor)
+            typenode->lifecycle.destructor(&typenode->nodeId, typenode->context,
+                                           nodeId, node->context);
+    } else if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+        const UA_VariableTypeNode *typenode =
+            getVariableNodeType(server, (const UA_VariableNode*)node);
+        // todo: writing the new context
+        if(typenode && typenode->lifecycle.destructor)
+            typenode->lifecycle.destructor(&typenode->nodeId, typenode->context,
+                                           nodeId, node->context);
     }
 
     /* Remove references to the node (not the references in the node that will
@@ -1503,7 +1511,8 @@ setValueCallback(UA_Server *server, UA_Session *session,
 }
 
 UA_StatusCode
-UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
+UA_Server_setVariableNode_valueCallback(UA_Server *server,
+                                        const UA_NodeId nodeId,
                                         const UA_ValueCallback callback) {
     UA_RCU_LOCK();
     UA_StatusCode retval =
@@ -1530,32 +1539,85 @@ setDataSource(UA_Server *server, UA_Session *session,
 }
 
 UA_StatusCode
-UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
+UA_Server_setVariableNode_dataSource(UA_Server *server,
+                                     const UA_NodeId nodeId,
                                      const UA_DataSource dataSource) {
-    UA_StatusCode retval = UA_Server_editNode(server, &adminSession, &nodeId,
-                                              (UA_EditNodeCallback)setDataSource,
-                                              &dataSource);
+    UA_RCU_LOCK();
+    UA_StatusCode retval =
+        UA_Server_editNode(server, &adminSession, &nodeId,
+                           (UA_EditNodeCallback)setDataSource,
+                           &dataSource);
+    UA_RCU_UNLOCK();
     return retval;
 }
 
-/****************************/
-/* Set Lifecycle Management */
-/****************************/
+/************************/
+/* Lifecycle Management */
+/************************/
+
+/* Global lifecycle */
+void
+UA_Server_setNodeLifecycle(UA_Server *server,
+                           UA_NodeLifecycle lifecycle) {
+    server->nodeLifecycle = lifecycle;
+}
 
 static UA_StatusCode
-setOLM(UA_Server *server, UA_Session *session,
-       UA_ObjectTypeNode* node, UA_ObjectLifecycleManagement *olm) {
-    if(node->nodeClass != UA_NODECLASS_OBJECTTYPE)
-        return UA_STATUSCODE_BADNODECLASSINVALID;
-    node->lifecycleManagement = *olm;
+setNodeTypeLifecycle(UA_Server *server, UA_Session *session,
+                     UA_Node* node, UA_NodeTypeLifecycle *lifecycle) {
+    if(node->nodeClass == UA_NODECLASS_OBJECTTYPE) {
+        UA_ObjectTypeNode *ot = (UA_ObjectTypeNode*)node;
+        ot->lifecycle = *lifecycle;
+        return UA_STATUSCODE_GOOD;
+    }
+
+    if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
+        UA_VariableTypeNode *vt = (UA_VariableTypeNode*)node;
+        vt->lifecycle = *lifecycle;
+        return UA_STATUSCODE_GOOD;
+    }
+    
+    return UA_STATUSCODE_BADNODECLASSINVALID;
+}
+
+UA_StatusCode
+UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
+                               UA_NodeTypeLifecycle lifecycle) {
+    UA_RCU_LOCK();
+    UA_StatusCode retval =
+        UA_Server_editNode(server, &adminSession, &nodeId,
+                           (UA_EditNodeCallback)setNodeTypeLifecycle,
+                           &lifecycle);
+    UA_RCU_UNLOCK();
+    return retval;
+}
+
+UA_StatusCode
+UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void **context) {
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
+    if(!node)
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+
+    *context = node->context;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+editNodeContext(UA_Server *server, UA_Session* session,
+                UA_Node* node, void* handle) {
+    node->context = handle;
     return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode
-UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server, UA_NodeId nodeId,
-                                                UA_ObjectLifecycleManagement olm) {
-    UA_StatusCode retval = UA_Server_editNode(server, &adminSession, &nodeId,
-                                              (UA_EditNodeCallback)setOLM, &olm);
+UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void *context) {
+    UA_RCU_LOCK();
+    UA_StatusCode retval =
+        UA_Server_editNode(server, &adminSession, &nodeId,
+                           (UA_EditNodeCallback)editNodeContext, context);
+    UA_RCU_UNLOCK();
     return retval;
 }
 
@@ -1565,34 +1627,24 @@ UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server, UA_NodeId nod
 
 #ifdef UA_ENABLE_METHODCALLS
 
-typedef struct {
-    UA_MethodCallback callback;
-    void *handle;
-} addMethodCallback;
-
 static UA_StatusCode
 editMethodCallback(UA_Server *server, UA_Session* session,
-                   UA_Node* node, const void* handle) {
+                   UA_Node* node, void* handle) {
     if(node->nodeClass != UA_NODECLASS_METHOD)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    const addMethodCallback *newCallback = (const addMethodCallback *)handle;
     UA_MethodNode *mnode = (UA_MethodNode*) node;
-    mnode->attachedMethod = newCallback->callback;
-    mnode->methodHandle   = newCallback->handle;
+    mnode->method = (UA_MethodCallback)handle;
     return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode
-UA_Server_setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId,
-                                 UA_MethodCallback method, void *handle) {
-    addMethodCallback cb;
-    cb.callback = method;
-    cb.handle = handle;
-
+UA_Server_setMethodNode_callback(UA_Server *server,
+                                 const UA_NodeId methodNodeId,
+                                 UA_MethodCallback method) {
     UA_RCU_LOCK();
     UA_StatusCode retval =
-        UA_Server_editNode(server, &adminSession,
-                           &methodNodeId, editMethodCallback, &cb);
+        UA_Server_editNode(server, &adminSession, &methodNodeId,
+                           (UA_EditNodeCallback)editMethodCallback, method);
     UA_RCU_UNLOCK();
     return retval;
 }