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
Overriding FileDirectoryType methods and MassSpectrometerDeviceType methods
March 13, 2020
8:35, EET
Avatar
Hashrin
Member
Members
Forum Posts: 8
Member Since:
March 6, 2020
sp_UserOfflineSmall Offline

Hi,

My query is a bit long and consists of two parts. Kindly bear with me:

1) File operations:

I’m trying to implement file operations using the Prosys OPC UA sample server and client classes. For that, I need to create a file from the client first. The problem is,
since FileDircetoryType, FileDirectoryTypeNode, and FileDirectoryTypeNodeBase classes don’t have generated codes, I can’t access their code files. Hence, I tried extending a FileDirectoryTypeChildNode class from the FileDirectoryTypeNode class and overrode the CreateFile method. Then, in the MyNodeManager class, I instantiated the FileDirectoryTypeNode class using two different approaches:

1.1) First approach:

private FileDirectoryTypeNode myFileDirectory;
final NodeId fileDirectoryId = new NodeId(ns, “MyFileDirectory”);
myFileDirectory = createInstance(FileDirectoryChildTypeNode.class, “MyFileDirectory”, fileDirectoryId);
this.addNodeAndReference(myFilesFolder, myFileDirectory, Identifiers.Organizes);

When I try to call the CreateFile from the client, my overridden method is not getting called. I think the overridden method inside FileDirectoryType class is getting called instead.

1.2) Second approach:

private FileDirectoryChildTypeNode myFileDirectory;
final NodeId fileDirectoryId = new NodeId(ns, “MyFileDirectory”);
myFileDirectory = createInstance(FileDirectoryChildTypeNode.class, “MyFileDirectory”, fileDirectoryId);
this.addNodeAndReference(myFilesFolder, myFileDirectory, Identifiers.Organizes);

This approach results in an error stating that FileDirectoryType cannot be cast to FileDirectoryChildType.

My fix:
The only way through which I can use my implementation of the overridden methods is when I create listeners for them in the server. This results in my listener getting executed when the client calls the corresponding method. Is that how it’s supposed to be for classes that don’t have generated codes?

2) MassSpectrometerDeviceType operations:

I used the codegen tutorial to generate DI and ADI classes. I need to implement methods inside the MassSepctrometerDeviceTypeNode class. I instantiated an object of MassSpectrometerDeviceTypeNode, and I’m able to view all the components inherited by it from the AnalyserDeviceType when I browse from the client. I need to override the methods in the MethodSet. But the generated codes don’t have the overridden methods. The only thing I could find was a getParameterSetNode() method in the AnalyserDeviceNodeBase class. Am I missing something here?

Thank you

March 13, 2020
11:30, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1026
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

Good Questions.

I’ll answer this in 2 parts, first for the 1. question. Note that I might simplify some parts, ask if unclear.

The Class parameter for createInstance is only used to search the TypeDefinitionId annotation on the class (or the first super class that has one) so that it can create a NodeBuilder instance. Plus the cast on return.

While that way is technically possible to get to work (see “As a last resort” in https://forum.prosysopc.com/forum/opc-ua-java-sdk/override-standard-condition-method/, and note the P.S. section why generally subtyping is not a good generalized solution; might still work for you), I would not recommend that unless the below is not an acceptable solution:

We do have an alternative way to make method impls for these cases. For the server side, the codegen creates for each UA Method in the model an interface TypeNameMethodNameMethod, for this case e.g. FileDirectoryTypeCreateFileMethod. Its parameters include the “FileDirectoryTypeNode node”. Create an implementation of this interface and call the static method FileDirectoryTypeNodeBase.setCreateFileMethodImplementation(instance_of_your_impl_here). SDK will then call that for you whenever the method is called (note that then the equivalent method in the XXXTypeNode is not called). Additionally, since statics can be seen via subtypes in java, I might call this via FileDirectoryTypeNode instead of the XXXNodeBase, but either works.

Let me know if that works for you. Also please remember to A) sanitize user inputs for file paths and, where needed B) build some kind of user auth control to prevent anyone connecting (depends of course on security modes) + calling those methods and e.g. deleting a file (or well any file on the system if A is not properly done).

And Short answer to 2. is that the DI model is semantically broken in my personal opinion. In practice that wont be possible via codegen (at least in short-term future, long term, maybe, but preferably not, but this needs a long explanation), you will need to use the listeners like in the “My fix” for 1. But I’ll write a better answer, might take a while.

March 13, 2020
14:37, EET
Avatar
Hashrin
Member
Members
Forum Posts: 8
Member Since:
March 6, 2020
sp_UserOfflineSmall Offline

Hi Bjarne,

Thanks for the timely reply and the effort you always put in resolving every issue posted here. Part 1 of my query was solved by implementing the interface as given in your instructions. I didn’t have to use subtyping after all. I will use listeners for part 2 as you suggested.
On another note, I don’t know much regarding user authentication since I’m new to OPC UA, but I will look into it. I remember seeing a section for that in the Prosys tutorial.

March 13, 2020
16:29, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1026
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Thanks 🙂

You can also look at MyUserValidator (in sampleconsoleserver). While that is half of the picture, it shows how to check the session user, plus you will need that anyway so that user can login properly in the first place (i.e. you need to have a user auth system). Then the second half is that you get the Session from the ServiceContext and check the user is allowed to do the Call.

And continuing for 2. This is long and complicated, but this might still be useful to have written like this in any case (even if you do not need this) so that I can point out to this in the future (some day we will do proper FAQ etc..). Also I’m open for suggestions on improving this, but preferably we would not do e.g. anything that is specific for the DI model alone (it might still come to that in the end, but we’ll see).

Codegen and the generated classes operate only using “1-level deep” operations. So does basic object oriented programming. If I build a small basic java example here:

Lets say we have classes: A, B, C and then a subtyped version of each: AS, BS, CS. Additionally they have the following methods:
– A.getB(), returns B
– B.getC(), returns C
– AS.getB(), returns BS (i.e. overrides the method)
– BS.getC(), returns CS (i.e. overrides the method)

If you then have an instance of AS, you can call for it of course as.getB().getC() and you would get a CS instance. Also it is impossible to get a “C” directly from A, you always have to go trough B (of course there can be a special method A.getC() that internally calls getB().getC(), but that is something you need to implement i.e. know that you need to implement it).

However we cannot “magically” make an instance of B.getC() API-wise to show that it would return “CS”, it does always return “C”, i.e. we can only change the signature by subtyping B, it is not possible to change any instance of directly B. Put in other words, java does not support “monkey patching” like dynamic programming languages may allow, i.e. you cannot add methods to an existing object you already have (I’ll skip Proxy etc. related systems). In OPC UA you however can. TypeDefinitions have so called InstanceDeclaration of other types. And it has subtyping rules for them that allows to add e.g. UA Methods. However since the codegen is designed to return “API-wise” the TypeDefinition-generated Class per InstanceDeclaration, that of course misses the Methods added by the InstanceDeclaration.

In theory we could fix this if we would codegen a java class per each InstanceDeclaration. But the number of classes generated from types alone is already quite much (and yes, we could maybe filter InstanceDeclarations that do not add anything to it’s TypeDefinition). Still in my opinion the more proper way would have to model proper subtype TypeDefinitions for these cases for any InstanceDeclaration of importance.

Now to why DI model is “broken” (and ADI since it uses it), the MassSpectrometerDeviceType:
It doesn’t itself contain MethodSet, but the its supertype AnalyserDeviceType has it (no problem). That MethodSet has e.g. the GetConfiguration method. That MethodSet HasTypeDefinition Reference points to BaseObjectType (is problem; also it should be noted that the MethodSet InstanceDeclaration node that is being overriden is also BaseObjectType in the TopologyElementType, that is the super type for all of those). BaseObjectType doesn’t define any Methods.

Therefore if we treat the AnalyzerDeviceType as “AS” in the java example, the MethodSet as “B” and the GetConfiguration as “CS”, it is API-wise impossible to get the CS from “B”, since the very type definition of B doesn’t have it. Note that the example analogy is not 1:1, since the original BaseObjectType doesn’t have any Methods (so “C” means nothing in this case).

Additionally as extra “problem”, it should be noted that since in OPC UA you always use the Object’s NodeId for which the Method is attached to in the Call servicecall, you must actually use the MethodSet NodeId when calling the methods, NOT the DeviceType NodeId (this is mentioned in the DI specification).

That and the generation problem could have been avoided, if the Methods were directly attached with HasComponent References to the DeviceTypes instead (they could even have been added e.g. with Organizes to the MethodSet even then). However in practice it is too late to change the existing logic, since the DI model is one of the most used companion specifications. Additionally there might be some edge-cases that I have missed where the above “simplification” would not work.

March 16, 2020
8:46, EET
Avatar
Hashrin
Member
Members
Forum Posts: 8
Member Since:
March 6, 2020
sp_UserOfflineSmall Offline

Hi,

Thanks for the extra information. I will go through the sample code to check how user authentication works. Regarding the MethodSet, I get the gist of what you’re saying.

“That and the generation problem could have been avoided, if the Methods were directly attached with HasComponent References to the DeviceTypes instead (they could even have been added e.g. with Organizes to the MethodSet even then).” – I had the exact same thought while browsing through the AddressSpace using UaModeler. Since it’s too late for the OPC Foundation to do anything about it, I’ll proceed with the listeners, since that works.

Thank you

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 1919

Currently Online:
22 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: 1523

Posts: 6449

Newest Members:

rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerley, Thomassnism, biancacraft16

Moderators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0

Administrators: admin: 1