Client side handling of Complex Structure

Questions regarding the use of the C++ SDK for Server or Client development or integration into customer products ...

Moderator: uasdkcpp

Post Reply
yvesP
Sr. Member
Sr. Member
Posts: 15
Joined: 13 Feb 2017, 14:15

Client side handling of Complex Structure

Post by yvesP »

Hi,
I've defined a new structure type e.g. MyCompositeType, using UAModeler, composed of other structured types:
MyComposite
|'member1' =of type MySubStructureA
|'member2' =of type MySubStructureB

What is the most efficient/elegant/recommended way of handling this information on client side?

The 'printExtensionObjects' method seems to reconstruct the composite recursive structure on client side and the resulting 'UaGenericStructureValue' is to be accessed by using iterating through the composition using the Name of the members.
Is there an alternative way supported? I've tried using the generated MyComposite(ExtensionObject) constructor on the client but that only seems to work for datatypes which are of type OpcUa_ExtensionObjectEncoding_EncodeableObject. Moreover as far as I can tell it takes a binary copy of the transported data, which might turn out to be a problem if the client and server evolve independently ( e.g. MyComposite gets extended with field on Server side).
The UaGenericStructureValue-approach would work but I just like to have confirmation whether I'm using the only correct way.
Kind regard.
Yves

User avatar
Support Team
Hero Member
Hero Member
Posts: 3070
Joined: 18 Mar 2011, 15:09

Re: Client side handling of Complex Structure

Post by Support Team »

Hello Yves,

there are 2 use cases you need to consider:

1) The structures are known at compile time:
You can work with the UaModeler generated classes e.g. MyComposite class.
All the knowledge of how the structure is encoded and decoded, which fields are available and so on is contained in the generated C++ code.
The advantage is that it's handy and easier to work with the C++ classes.
See sample client code printExtensionObjectKnownType().

2) The structures are dynamically created in the server or not know in the client:
The client needs to obtain all the information about the structures during runtime by reading this information from type dictionary (or DataTypeDefinition Attribute in future versions). The advantage is that this implementation can handle any structure from any server.
See sample client code printExtensionObjectGeneric().

So it's basically a decision of how generic your client needs to work.
For a project specific solution where all types are defined and known at compile time you can go for option 1.
For a generic solution (i.e. the client should be abel to handle any structure) you need to go for option 2.
As shown in the sample client you can have a combination of both by implementing a special handling for known structure types and also providing a generic implementation.
Best regards
Unified Automation Support Team

marc.fuerst
Jr. Member
Jr. Member
Posts: 4
Joined: 18 Jan 2017, 11:22

Re: Client side handling of Complex Structure

Post by marc.fuerst »

Hi,

I found this post while searching for a solution to my problem.
I would like to go with the first solution. This works fine for scalar custom types. With a one dimensional array I'm not able to parse the data out of the array objects with the first method.
I debugged it and figured out, that the ExtensionObjects inside the ExtensionObjectsArray are of NodeId <MyStructuredArrayVariable>_Encoding_DefaultBinary and not of <MyStructuredArrayVariavle>.
I tried different ways. First I tried to use the method mentioned in the client example with printExtensionObjectKnownType. Then I tried the constructor of <MyStructuredType>s with the UaVariant containing the UaExtensionObjectArray. Neither of the methods work, because the Encoding for both atemps was ObjectBinary and not EncodableObject.
On server side everything seems to work fine, because with UaExpert I am able to see the array variable of custom type of my object, with the correct TypeIds.

Any idea, what I'm doing wrong here?

yvesP
Sr. Member
Sr. Member
Posts: 15
Joined: 13 Feb 2017, 14:15

Re: Client side handling of Complex Structure

Post by yvesP »

Hi,
@support team:
am I right to conclude that option1 can be used when client is sure that it has a 100% exact Type description at compile time?

As in most Client Server models both ends can be deployed and evolve separately. For instance in time a new version of the server could be deployed which has an additional field (just extending, not modifying) in a datatype T. At that point I guess it would break the client since the constructor of T(ExtensionObject) does a binary copy of the datablob send by the Server.
The equivalent of what you have in COM IDL, an optional parameter with a default, is not supported in OPC-UA?
Kind regards.
Yves

User avatar
Support Team
Hero Member
Hero Member
Posts: 3070
Joined: 18 Mar 2011, 15:09

Re: Client side handling of Complex Structure

Post by Support Team »

Yes if you want to use the generated classes you need to have the exact definition at compile time.
For any other case you need to work the generic way.
Best regards
Unified Automation Support Team

marc.fuerst
Jr. Member
Jr. Member
Posts: 4
Joined: 18 Jan 2017, 11:22

Re: Client side handling of Complex Structure

Post by marc.fuerst »

Got the fix for my problem.

As a hint, for your custom structured types, if you have generated code, you have to call <MyNamespace>::DataTypes::registerStructuredTypes().
It's in datatypes.h/cpp
For the server side, this is done in the afterStartup() method of the autogenerated server code (NodeManagerBase).
For client side, there is no "running" code generated. So you have to do this yourself.
Took me quiet a little to figure this out, because the documentation for generated code usage and custom structured type usage is a little "lightweight" at the moment.

Best regards.

User avatar
Support Team
Hero Member
Hero Member
Posts: 3070
Joined: 18 Mar 2011, 15:09

Re: Client side handling of Complex Structure

Post by Support Team »

You are right you need to call registerStructuredTypes() for each namepsace where you added your own datatypes.
Thank you for your feedback and sharing this with other users.
Best regards
Unified Automation Support Team

Post Reply