Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
OPC UA Client error after upgrade to SDK 5.1.0
March 5, 2024
11:16, EET
Avatar
hbrackel
Member
Members
Forum Posts: 135
Member Since:
February 21, 2014
sp_UserOfflineSmall Offline

Good morning,

After upgrading the SDK from 4.10.x to 5.1.0, my OPC UA clients log the following error

AbstractUaNodeFactory – Could not resolve super type as UaType, typeId: nsu=http://opcfoundation.org/UA/;i=0

This (seemingly?) prevents any further handling of server-side data structures. So, for example, The BuildInfo Node cannot be „cast“ to BuildInfoType rather remains a UaVariableImpl type.

The typeDictionary init/refresh is performed manually.

Any hints or suggestions on what causes the problems are much appreciated.

March 5, 2024
14:25, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

Unfortunately that log line doesn’t do a stacktrace, but do you know what SDK method did you call when this happened? e.g. was it while AddressSpace.getNode specifically OR something from: TypeDictionary.init or AddressSpace.getNodes (this works differently than the getNode) or UaNode.getComponents()?

Is the server made with our SDK (are you also updating that?) or something else? Is it possible to check does it send HasTypeDefinition References for some other NodeClasses that Object+Variable?

Possibly we might need to continue via email with a beta version with more logging if that doesn’t help.

Technically the ERROR comes from a logic that tries to ensure the most-codegenerated supertype is used when the type itself is not, but here basically either there is a missing TypeDefinition (effectively that nsu=http://opcfoundation.org/UA/;i=0 is NodeId.Null, but in SDK specific “UaNodeId format”) and SDK uses the NodeClass-based fallback (thus the cast error) or alternatively for some reason this arrived instead of the plain java-null (in which case it only uses the NodeClass-based), which probably would be a bug.

March 6, 2024
9:41, EET
Avatar
hbrackel
Member
Members
Forum Posts: 135
Member Since:
February 21, 2014
sp_UserOfflineSmall Offline

Hi,

there is unfortunately no stacktrace coming with the log entry (even though stack trace info has been enabled).

The server, which the client connects to, is not a Prosys based server. That said, it is an aggregationServer which aggregates (mirrors) a Prosys based OPC UA servers amongst many others, in its addressSpace.
The underlying Prosys server has also been migrated from SDK 4.10.x to 5.1.0 and it contains a lot of generated code with some overrides / additions in the generated Impl class files.

I added additional logging to the AbstractUaNodeFactory class. Since then, the exact problem described above did (probably coincidently) no longer shows up. Further analyzing the problem I found that a prior subscription of a custom structured dataValue delivers the following “GOOD” value:

DataValue(value=ExtensionObject [typeId=nsu=invalid_missing_namespacearray_uri_for_index:39;i=5001, encodeType=Binary, object=[28] 0x07000000345638504331500500000052554e2034ae979a779ca2cb3f], statusCode=GOOD (0x00000000)….

Is the “invalid_missing_namespacearray”… inserted by the Prosys Client or by the server, which delivers the subscribed values? Reading out the namespaceArray before the first value is returned shows that all namespaceArray entries are present..

Edit:

the invalid_missing_namespacearray_uri_for_index is coming form the Prosys client NamespaceTable class. As mentioned before, I read all the correct namespaces from the namespaceTable before the first values has been returned from the siubscription, but after the subscription (and monitored items) have been created. Is the subscription possibly caching the namespaceTable?

Edit 2:

I found that the namespace table is only updated at the time the client connects to the server, which means any namespace additions are not recognized, while the types can be refreshed. What would be nice is a method call to update the namespascetable “on demand”

March 6, 2024
14:32, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

(I did see you made the EDIT 2, but this was written without that knowledge)

This is somewhat complicated, so a long post and I think this wont be enough, but maybe it gives some ideas.

An aggregating server complicates things. That also makes it more likely to have a scenario where the NamespaceArray changes. In general we assume it to be a constant, it is read once during UaClient.connect() and then that is used. It is possible to re-read it via UaClient.getNamespaceTable(true) (and then the new one is cached). But data from the unknown namespaces could sort of be invalid and also note that if any position of a NamespaceUri would change in the NamespaceArray any index could be invalid.

5.1.0 does re-read the NamespaceTable if it is re-creating monitored items after a reconnect for items that were successful in the past connections to make items made with ExpandedNodeId work (and this assumes also that their namespace would not be directly visible immediately after connect). I think it would be nice IF we could something similar if we enounter unknown indexes while decoding a Message. However, that would be more complicated as an invalid server could potentially then cause us to basically forever-re-read it, which probably wouldn’t be desired, but this is something we must think..

So, in short currently you must manually re-read the NamespaceTable via UaClient.getNamespaceTable(boolean).

The invalid_missing_namespacearray_uri_for_index:X pattern comes from the SDK itself as you noted. It is used as a fallback if there isn’t an uri for the index X in the NamespaceTable (i.e. server NamespaceArray). It allows some operations to still work when the server has an invalid NamespaceArray. However, this was done in 4.3.0 (https://downloads.prosysopc.com/opcua/Prosys_OPC_UA_SDK_for_Java_4_Release_Notes.html#version-4-3-0): “Changed: NamespaceTable conversion from indexes, that are not in the table, now results in a special “invalid uri” syntax, which will be converted back to the original index when needed. Thus conversion from NodeId to ExpandedNodeId will no longer break if the index is not known. This change also applies to UaNodeId.”

It is possible there is some unknown interaction that isn’t fully working, but I think receiving that invalid_missing_namespacearray_uri_for_index:X ExtensionObject would have happened already from 4.3.0 onwards. Though, 5.x uses more UaNodeId, e.g. the serialization is now based on the DataTypeIds represented as UaNodeId (previous versions used Java Class mappings which did cause issues with DynamicStructure.class).

One possible workaround to decoding it would be com.prosysopc.ua.stack.builtintypes.ExtensionObject.getTypeId(), com.prosysopc.ua.stack.common.NamespaceTable.toNodeId(ExpandedNodeId) and back com.prosysopc.ua.stack.common.NamespaceTable.toExpandedNodeId(NodeId) and com.prosysopc.ua.stack.builtintypes.ExtensionObject.ExtensionObject(ExpandedNodeId, ByteString). Assuming the NamespaceTable after a refresh has the uris in the same indexes the unknown index X pattern would get index X, then the real NamespaceUri. If you did init the TypeDictionary after a manual NamespaceTable refresh, it would only know the metadata with the correct Namespace, not by the invalid pattern.

P.S.
To the previous problem it is possible that the aggregation wouldn’t “flatten” the 0-core-namespace. This could cause a situation where a HasTypeDefinition target wouldn’t inherit from the 0-ns-types, but instead of an “aggregated 0-ns” that is in different index, which would be invalid, as all Object and Variable types must inherit from BaseObjectType and BaseVariableType (thus a super-type search would always find the SDK-internal codegen representation of the core namespace and use those).

March 6, 2024
20:28, EET
Avatar
hbrackel
Member
Members
Forum Posts: 135
Member Since:
February 21, 2014
sp_UserOfflineSmall Offline

I really appreciate your support and patience on this subject.

Adding the getNamespaceTable(true) call indeed resolves the namespaceArray problem. Thanks a lot for the hint. Which leaves me with the next challenge. Now that the namespaceTable has been reloaded, the typeDictionary has been refreshed, casting an ExtensionObject to a DynamicStructure (the dataValue is a known-to-be custom structure dataType) fails, even though ExtensionObject.getTypeId() returns the expected value. The same cast succeeds after a manual disconnect and reconnect of the client. Is there possibly anything in the decoder which might require a refresh as well?

This last error is not related to the SDK upgrade to 5.1.0. I actually upgraded the SDK version hoping that the unsuccessful cast problem would be resolved.

On your “PS” concern: The aggregationServer correctly “flattens” the ns=0 namespace. Wink. The positions of the namespaceUris in the namepsaceArray will never changes, as this is forbidden by the specification. New namespaces will eventually only be appended to the namespaceArray.

March 7, 2024
14:38, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

The ExtensionObject.getObject() doesn’t decode, it just returns whatever is in the value (if it is encoded, it remains the encoded object). If you wish to try to decode again, you must do so via the .decode(client.getEncoderContext()) instead. Hopefully, just this is needed as it would explain it. If not then not yet sure why.

General explanation of how it goes:
When the SDK receives ExtensionObjects, the BinaryDecoder will attempt to decode them. If they are within a Variant, on a successful decode the decoded Structure is set in the Variant instead (or if an array then SDK will calculate the most-sub-type array that can hold the values (raw Structure-array if needed)). If it is a Structure field, it must remain as ExtensionObject (as the field has that type in Codegen classes and DynamicStructure represents them similarly), but it uses the ExtensionObject(Structure) constructor that just holds the decoded value (thus getObject would return it). If the decoding doesn’t work, the encoded ExtensionObject form is kept so you can still have some access to the data and possibly decode it later, but it doesn’t hold on the context so that is why it must be given via the .decode(context).

Note that if UaClient.isInitTypeDictionaryAutoUsage() is true (the default) it will try to resolve the metadata via the OPC UA 1.04 DataTypeDefinition Attribute (only works if server is at least 1.04 and supports this feature) during decoding. I must note that it is very likely that you do have that as the default (so maybe the aggregation server doesn’t translate the DataTypeDefinition read, or the “source server” here wasn’t the one made with our SDK so it might not yet support it), because I did find a regression bug 4.x->5.x if it is false. The idea was that TypeDictionary.decode(ExtensionObject) could be used to decode if the InitTypeDictionaryAutoUsage is false (this means in practice that the EncoderContext is not linked to the TypeDictionary by the UaClient), but that wont work currently as now it works only in the linked mode. We’ll need to fix this, but it shouldn’t affect this case.

March 12, 2024
15:10, EET
Avatar
hbrackel
Member
Members
Forum Posts: 135
Member Since:
February 21, 2014
sp_UserOfflineSmall Offline

Hello,

I would just like to close this topic out by providing some information about what finally proved to work:

  • there was a sporadical bug in the aggregation server in that it sometimes missed a reference to the encoding. After fixing that,
  • I found, that only the exact combination of
    • uaClient.isInitTypeDictionaryOnConnect = true
    • uaClient.isInitTypeDictionaryAutoUsage = true
    • uaClient.typeDictionary.refresh() after sensing the completion of the aggregation

worked as desired. Any other combination of …OnConnect and …AutoUsage did not show the expected type decoding.

Thank you very much again for you wonderful support.

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 518

Currently Online:
23 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

hbrackel: 135

pramanj: 86

Francesco Zambon: 81

rocket science: 77

Ibrahim: 76

Sabari: 62

kapsl: 57

gjevremovic: 49

Xavier: 43

fred: 41

Member Stats:

Guest Posters: 0

Members: 682

Moderators: 16

Admins: 1

Forum Stats:

Groups: 3

Forums: 15

Topics: 1467

Posts: 6261

Newest Members:

karrimacvitie5, graciela2073, sagarchau, elviralangwell4, Donnavek, Eddiefauth, DonaldPooma, fidelduke938316, Jan-Pfizer, DavidROunc

Moderators: Jouni Aro: 1010, Otso Palonen: 32, Tuomas Hiltunen: 5, Pyry: 1, Petri: 0, Bjarne Boström: 983, Heikki Tahvanainen: 402, Jukka Asikainen: 1, moldzh08: 0, Jimmy Ni: 26, Teppo Uimonen: 21, Markus Johansson: 42, Niklas Nurminen: 0, Matti Siponen: 321, Lusetti: 0, Ari-Pekka Soikkeli: 5

Administrators: admin: 1