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