8:40, EEST
February 21, 2014
Good morning,
I have generated code, which comprises object nodes, which have optional objectNode children, which in turn have optional variables. While the use of the TypeDefinitionBasedNodeBuilderConfiguration as described in the server tutorial works well for child variables, I wasn’t successful in creating child objects this way. So my question is, how can I configure the node builder for optional object nodes and in turn their children? (possibly even a deeper hierarchy).
Thanks,
Hans-Uwe
PS: I’m using SDK 3.0.0
10:57, EEST
April 3, 2012
Hi Hans-Uwe,
In general it should not be any difference about Variables vs. Objects in this case. As a test, does the node appear, if you set the setInstantiateAllOptionals(true) in the TypeDefinitionBasedNodeBuilderConfiguration builder?
However depending on how the type is defined, it might fall into another (complex) category, in short:
Let A be type that has an optional node X having TypeDefinition B.
Let B be type that has an optional node Y having TypeDefinition C.
It is possible to construct the nodes for type A in 2 different ways.
1A: A -HasComponent-> X (Typedef B) -HasComponent-> Y (Typedef C)
1B: B -HasComponent-> Y (Typedef C)
1C: C
2A: A -HasComponent-> X (Typedef B) (note missing reference to Y here)
2B: B -HasComponent-> Y (Typedef C)
2C: C
The short answer is that if A is defined as in 1A, then it is possible to instantiate A with C with NodeBuilder. However if it is defined as 2A, then by default it is not possible. (longer is that is is doable, but there are some edge-cases and possible problems, I will answer later after I know the situation)
15:10, EEST
February 21, 2014
Hi Bjarne,
my setup is of the kind
ObjectTypeA has an optional node ObjectB of ObjectTypeB
ObjectTypeB has an optional variable “VariableInB” of BaseDataVariableType
conf.addOptional(
UaBrowsePath.from(SdkTestIds.ObjectTypeB, UaRelativePath.from(UaQualifiedName.from(testNamespaceUri, "VariableInB"))),
UaBrowsePath.from(SdkTestIds.ObjectTypeA, UaRelativePath.from(UaQualifiedName.from(testNamespaceUri, "ObjectB")))
)
testNodeManager.nodeBuilderConfiguration = conf.build()
val objA = testNodeManager.createInstance(ObjectTypeANode::class.java, "ObjectA", nodeId)
The Kotlin code above creates an ObjectA instance containing an ObjectB, but the ObjectB does not contain the VariableInB. I also tried a relativeBrowsePath including both ObjectB as well as VariableInB, different ordering, as well as setinstantiateAllOptionals=true. Another attempt to use a nodeBuilder specific configuration gave the same result. It also doesn’t make a difference, whether the browse paths are in a single addOptional() or individual addOptional() calls.
Could you eventually provide a little code snippet which demonstrates the “best practices” of creating hierarchical optional node structures (if the above is not how it should be done)?
Thanks,
Hans-Uwe
18:05, EEST
April 3, 2012
Hi,
That should be correct (but I can doublecheck tomorrow, also sorry if this post is a bit messy, as the subject is not that trivial.. I should really write a blog post / better tutorial..).
The thing I pointed out with the “2 different ways” is that what is the actual node structure in the Types part of the address space, is it option 1 or 2? i.e. (a bit simplified, but should work in this case), is it possible to find a node “VariableInB” by starting from the ObjectTypeA node and (ONLY) going forward (I guess HasComponent) references? If yes, then it is option 1, if not it is 2. Since you still have the problem I would assume it is 2 (which does not work directly out-of-the-box).
The instantiation system / NodeBuilder uses the Types address space nodes when instantiating and normally it can only instantiate InstanceDeclrations that are found when looking at a Type node (+all supertypes) and it’s forward hierarchical references (the exact logic is based on the specification, v1.03 Part 3, section 6.4.2 “Creating an Instance”) . It does not look at the TypeDefinition of the InstanceDeclrations, which is why in the case of 2 when making the InstanceDeclarationHierarchy of ObjectTypeA it does not contain InstanceDeclaration for “VariableInB”.
There is a second “test”/workaround that also could be tried. Call InstanceDeclarationHierarchy.addInstanceDeclarationsTypeDefinitionOptionals = true (it is static public field) at the start of main (or before SDK interactions), does it work then? (if yes, then it is option 2). Note that it is experimental, not very well tested and causes problems if the same InstanceDeclaration node is found multiple times (NodeBuilder creates one instance node per InstanceDeclaration node) and also in theory can lead to infinite address space / out of memory if a complex optional node structure can lead to itself (e.g. linkedlist “node” style type could have infite chain instances of itself as optional).
IF the result of this was that the option 2 was true, then I recommend transforming the nodeset so that it becomes 1. If you are using UaModeler, you should be able to do this via selecting the optional ObjectB node in ObjectTypeA in the Information Model left down panel, then click on the “Select optional components” button below the Object section in the middle of the program, and select the “VariableInB”, then export the model and then it should work without the InstanceDeclarationHierarchy.addInstanceDeclarationsTypeDefinitionOptionals = true
18:57, EEST
February 21, 2014
Hi,
the nodeBuilder approach is very handy for straight forward tasks and in particular provides “BrowseName”-safety. As I will have to do more “nasty” things with the instances, such as updating (remove, change value, add) their optional components based on business object states, I’m now considering injecting the business objects into the Generated implementation classes and creating the optional components manually in the afterCreate() method. I guess that the effort is not much different compared to the “per node” creation of a NodeBuilderConfiguration.
I would have another related question: looking at the generated code, there is a static method setObjectxxxxeInitializer(…). Is this meant to be used by custom code or by a NodeBuilder?
Thanks,
Hans-Uwe
13:17, EEST
April 3, 2012
Hi,
Well there is a small semantical difference, if you make sub-nodes yourself from a TypeDefinition vs. instantiating it as part normal instatiation. Making the node yourself ignores possible overrides made to the InstanceDeclarations in the type. If you do not have overrides, then it should be semantically the same. Of course you can also modify the nodes after you have made them yourself so that they are identical. Overriding is explained in the spec v1.03, Part 3, section 6.3.3.3 “Overriding InstanceDeclarations”.
Using your setup as an example, the InstanceDeclaration found for path ObjectTypeA/ObjectB/VariableInB can/could contain overrides to the node “VariableInB” found via path ObjectTypeB/VariableInB. If you instantiate ObjectTypeB yourself and put it to ObjectTypeAInstance/ObjectB, then the node ObjectTypeAInstance/ObjectB/VariableInB is from the definition of ObjectTypeB, not from the ObjectTypeA. However this does not matter, if the node ObjectTypeA/ObjectB/VariableInB does not exist, or is identical to the node ObjectTypeB/VariableInB.
The static setXXXInitializer is intended to be an alternative way vs. editing the generated XXXTypeNode classes manually. See the code in XXXTypeNodeBase, if there is an implementation set, it will be called in the afterCreate method of the XXXTypeNodeBase. The same kind of logic is provided for making Method implementations, via the static setXXXMethodImplementation methods.
Most Users Ever Online: 1919
Currently Online:
14 Guest(s)
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Heikki Tahvanainen: 402
hbrackel: 144
rocket science: 88
pramanj: 86
Francesco Zambon: 83
Ibrahim: 78
Sabari: 62
kapsl: 57
gjevremovic: 49
Xavier: 43
Member Stats:
Guest Posters: 0
Members: 737
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1524
Posts: 6450
Newest Members:
fannielima, kristiewinkle8, rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerleyModerators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1