16:56, EET
February 21, 2014
Good afternoon,
I am looking for a way for an UaClient to read variable values from a server, where the DataType is based on a custom structure DataType. Unfortunately, the namespaces of the type definitions are occasionally updated (they contain the date/month of release), so I cannot use generated code across multiple versions of that server.
Is there a way for a client to dynamically “decode” a custom structure variable value at runtime using SDK support? I remember that v4.x.x of the SDK provides improved support for complex datatypes. It would be great, if you could provide a little code snippet, demonstrating how to decode a DataValue containing a custom structure.
Many thanks,
Hans-Uwe
18:25, EET
April 3, 2012
Hi,
(Long post, sorry, and I think there is a lot more that should be said, but maybe this will do for now, but yes, should be documented a lot better…)
This has been improving with each release. You’ll want version 4.2.0, that would be the best (https://downloads.prosysopc.com/opcua/Prosys_OPC_UA_SDK_for_Java_4_Release_Notes.html#version-4-2-0), unless you connect to an S7 device (see other latest threas of this forum since we have problems with that currently, in case try 4.1.4). Additionally it should be mentioned that with 4.2.0 connecting might take longer (this is currently directly related to the number of custom Structures since we need to read them all), working on improvements on that for the next release.. (which should be soon).
Basically as it is, any Structure can be handled like this, i.e. “dynamically”, since we enhanced the Structure interface to contain all relevant APIs from SDK’s DynamicStructure in 4.x. Note that this example is missing all error handling etc. This is something I can give right now, making a proper full example will take some time. Let me know if you encounter any issues.
UaClient client = …
Structure customStructure = (Structure ) client.readValue(nodeId).getValue().getValue();
StructureSpecification customStructureSpecification = customStructure.specification();
for (FieldSpecification fieldSpecification : customStructureSpecification.getFields()) {
// Getting values
Object fieldValue = customStructure.get(fieldSpecification);
// Setting values, the fieldSpecification contains meta-data for types
Object newValue = …;
customStructure.set(fieldSpecification, newValue);
}
i.e. meaning that the SDK is already doing it dynamically in the latest versions.
Additionally it should be mentioned that Structure has toBuilder which will return a Structure.Builder that will build instances of the same type (initializes with current values of fields). The same builder can obtained from the StructureSpecification.toStructureBuilder(). StructureSpecifications can be obtained from UaClient.getEncoderContext().getStructureSpecification(UaNodeId id) after connecting. And UaNodeId is an “upgraded” NodeId (has UaNamespace object instead of the index, and that in turn contains the namespaceuri; I’ll skip details for now, can be discussed later in some other post if needed), can be made with the static factory methods of that class (via NodeId/ExpandedNodeId + NamespaceTable from the client).
14:20, EET
February 21, 2014
15:04, EET
April 3, 2012
I might need clarifications on what exactly you mean by “caching” here.
StructureSpecification instances are immutable, SDK will keep track of them with the TypeDictionary and/or EncoderContext (basically EncoderContext will delegate to TypeDictionary if needed). If your value is always the same type, i.e. your MonitoredDataItemListener handler is not shared between items, then the Structure.specification() is the same java object each time.
9:46, EEST
February 21, 2014
Good morning,
I have finally been able to try out the code snippet below. (still on SDK v4.1.4). Unfortunately, I get a ClassCastException when trying to cast the ExtensionObject to the Structure interface. Any ideas how to circumvent this problem?
Thanks,
Hans-Uwe
NodeId nodeId = …
UaClient client = …
Structure customStructure = (Structure ) client.readValue(nodeId).getValue().getValue();
StructureSpecification customStructureSpecification = customStructure.specification();
for (FieldSpecification fieldSpecification : customStructureSpecification.getFields()) {
// Getting values
Object fieldValue = customStructure.get(fieldSpecification);
// Setting values, the fieldSpecification contains meta-data for types
Object newValue = …;
customStructure.set(fieldSpecification, newValue);
}
13:27, EEST
April 3, 2012
If you see an ExtensionObject, it means that the SDK was not able to decode the Structure (binary-wise they are transmitted as an ExtensionObject within the Variant) for some reason. An ExtensionObject itself is not a Structure, it instead contains the raw binary (or XML or JSON) data plus an encoding id (this is NOT the DataType NodeId). And in some cases within the our SDK it could also hold an already decoded Structure, but if you see an ExtensionObject like that (from the DataValue) then it is not decoded.
You can try passing that ExtensionObject to (UaClient) client.getTypeDictionary().decode(extensionObject). However you’ll most likely get an exception thrown if you received the ExtensionObject in the first place, since SDK should do that part automatically. Basically this API is from the era where this part was not automatic.
Most likely something prevented the TypeDictionary from being properly initialized. If that happened you should see an ERROR or WARN log when you did connect the UaClient. Some servers might define the metadata incorrectly (or it might be missing completely). In those case we cannot do much.
If at all possible, I would recommend to try with the latest version, 4.3.0. One of the main points was improving the initialization process of the TypeDictionary, thus the logging is a lot better there as well. If not all Structure types of the server could not be resolved to StructureSpecifications, it will log on WARN level which could not be resolved. IF the ExtensionObject.getTypeId() you received corresponds to the binary-encoding-id of one of the Structure types that could not be resolved then that is why. And note that the DataType NodeId is different from the binary-encoding-id NodeId (that is the NodeId of HasEncoding non-hierarchical reference target from the DataType that has the BrowseName “Default Binary”).
17:44, EEST
February 21, 2014
I finally upgraded to v4.3.0 of the SDK (took a moment, as I had to update a series of libraries as well). The problem has been solved . The structures are correctly recognized and are decodable using your coded snipped above. Really nice!
As a side effect (?), the strange timeout incidents discussed in another forum entry are no longer occurring. It has really been worth the upgrade.
Thank you very much for your continued support!!
Hans-Uwe
Most Users Ever Online: 1919
Currently Online:
15 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: 735
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1524
Posts: 6450
Newest Members:
kristiewinkle8, rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerley, ThomassnismModerators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1