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
Aaccessing object nodes from client
March 3, 2020
12:40, EEST
Avatar
agrillo
Member
Members
Forum Posts: 22
Member Since:
June 28, 2016
sp_UserOfflineSmall Offline

Hello,
I generated a new object (FiberPulser) with UaModeler and now I need to access its nodes from client (for example fiberCtrlStatus).
In the FiberPulserImpl.java I created two methods: one for the model registering and another to create a subscription to fiberCtrlStatus node (this last method calls the getFiberCtrlStatusNode() method required for subscription).
When I instantiate this new object and call the second method I obtain a NullPointer exception, because the getFiberCtrlStatusNode() method returns null.

Here is the code:

This is the FiberPulser instantiation:

int cameraNamespaceId = CameraClient.client.getNamespaceTable().getIndex("http://www.oact.inaf.it/OPCUA/…..");
AddressSpace addressSpace = CameraClient.client.getAddressSpace();

// Fiber Pulser
NodeId fpNodeId = new NodeId(cameraNamespaceId, "FibPulser");
QualifiedName fpBrowseName = null;
LocalizedText fpDisplayName = null;

try {
fpBrowseName = addressSpace.getNode(fpNodeId).getBrowseName();
fpDisplayName = addressSpace.getNode(fpNodeId).getDisplayName();
} catch (ServiceException | AddressSpaceException e) {
e.printStackTrace();
}

FiberPulser fiberPulser = new FiberPulserImpl(addressSpace, fpNodeId, fpBrowseName, fpDisplayName);

((FiberPulserImpl) fiberPulser).addFibPulserCtrlStatusSubscription(); //Eclipse forces this cast why?

And this is the FiberPulserImpl.java:


public class FiberPulserImpl extends FiberPulserImplBase {
private Subscription fpCtrlStatusSub;
protected NodeId fpCtrlStatusNodeId;

public FiberPulserImpl(AddressSpace addressSpace, NodeId nodeId, QualifiedName browseName, LocalizedText displayName) {
super(addressSpace, nodeId, browseName, displayName);
registerFpObjects();
}

public void registerFpObjects() {
CameraClient.client.registerModel(InformationModel.MODEL);
fpCtrlStatusNodeId = getFiberCtrlStatusNode().getNodeId(); //this is the line that gives error
}

public void addFibPulserCtrlStatusSubscription() {
try {
if (fpCtrlStatusSub == null) {
fpCtrlStatusSub = new Subscription();

CameraClient.client.addSubscription(fpCtrlStatusSub);
fpCtrlStatusSub.addItem(CameraClient.createMonitoredDataItem(fpCtrlStatusSub, fpCtrlStatusNodeId, Attributes.Value, dataChangeListener));

}
} catch (ServiceException | StatusException e) {
logger.error(e.getMessage());
}
}

Where am i wrong?
Thank you in advance.

Cheers.
Alessandro

March 3, 2020
15:38, EEST
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 491
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

(I’m assuming SDK 4.x)

That is prone to errors and some parts are incorrect. Sorry for sounding rude, but based on what did you end up code like that? Did you read the Codegen manual “Prosys_OPC_UA_SDK_for_Java_Codegen_Manual” in the ‘codegen’ folder that is in the SDK zip you downloaded? And then Chapter 18 in the Client tutorial as the manual refers to that on using the generated classes?

Anyway a short list of things that are wrong:
– The constructors of the generated classes should never be called manually!! This is really important! They are generated as protected for a reason (they might have been public in some older versions accidentally), SDK will call them for you (and must call). Each generated class models a single node (type). OPC UA types usually have a group of nodes. Basically everything goes wrong if you try to instantiate them manually (rest of nodes are basically “null”). Instead use the AddressSpace.getNode version that takes the Class parameter and pass the FiberPulseImpl.class (this is assuming you know the node is of that type, otherwise you will need to do instanceof etc checks)
– The model must be registered outside of the classes that would be registered, e.g. after creating the UaClient object would be a good place (anyway, before you call getNode so that it knows internally to return correct UaNode subtype, as those are what are generated), note that some of the generation targets will create proper services META-INF files that we’ll can use internally to automatically register the model for you when the client connects, see the manual for more info
– While not an error, I would not make the code for Subscriptions etc. within the node objects, since basically each UaNode object is a temporary object that encapsulates state from the server. Based on the AddressSpace.getCache parameters it will be recreated if it is too old when you next time call getNode (unless you hold a reference to it manually and use that instead)

So just do
0. Generate the model
1. Assuming you are not using the automatic model registration detection, call client.registerModel, otherwise it will be automatically found (assuming the generated resource files are within classpath)
2. Call client.getAddressSpace.getNode(nodeId, FiberPulseImpl.class) and use it

March 4, 2020
10:21, EEST
Avatar
agrillo
Member
Members
Forum Posts: 22
Member Since:
June 28, 2016
sp_UserOfflineSmall Offline

Hi Bjarne,
first of all thank you for your reply.
In our institution we are still using version 2.1.2-478 (we’re evaluating an update to 4.x) with a temporary client taken from the SDK sample, and only now we decided to create a definitive client using UaModeler.
Unfortunately the documentation accompanying this old version was not enough to clarify all my doubts, so I tried to improvise, but I already suspected that it wasn’t the correct way.
I suppose what you suggested me also applies to version 2, if not, please let me know.

Many thanks again and best regards.
Alessandro

March 4, 2020
13:01, EEST
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 491
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Oh, sorry, that explains a lot.

That is quite an old version, we (and OPC UA in general) have come a long way since (but there is still a lot to be improved at least documentation-wise…).
Basically for SDK 3.x we had to mostly rebuild the codegen pretty much from scratch. However the outputs are mostly the same (at least the core concepts are the same, 4.x did have other changes for the SDK, https://downloads.prosysopc.com/opcua/Prosys_OPC_UA_SDK_for_Java_4_Release_Notes.html#version-4-0-0 which also affected the outputs, e.g. “stack classes” are now part of the SDK etc.).

My suggestions should mostly apply to 2.x (but it has been so long, i.e. I might forget something). Anyway for that you will need to do the model registration manually, since automatic registration ‘client_model_provider’ ‘server_model_provider’ generation targets were added in 4.x. Also the registration might only work after UaClient.connect() has been called (but try after creating the UaClient first, if that gives an exception, then register after connect())

Also it should be noted that after 2.1.2 the generator did get some bugfixes in subsequent 2.x releases. Additionally, OPC UA 1.03 and 1.04 have added more features that the 2.x SDK nor it’s codegen cannot use (e.g. 1.03 added Structures with optional fields and Union Structures), i.e. if you try to generate a model that is using any 1.03 or 1.04 features or types any of the following could happen during generation: wont work, will fail silently or generates incorrect classes (e.g. since it doesn’t know optional structures are a thing, it would treat them as normal ones, so binary encoding would be incorrect). So generally I recommend to update to 4.x, where possible.

March 4, 2020
13:09, EEST
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 491
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Also I guess I should mention that due to improvements in the SDK, in 4.x latest versions it should be mostly possible to just skip the codegen step altogether. We can nowadays mostly handle any custom Structure/Enumeration with DynamicStructure/DynamicEnumeration (there are few edge-cases where codegen still might be needed, e.g. at least on the server side loading the model if you have a node has a custom Structure Value and the custom structure has a custom structure also it’s fields). Also any Structure can be handled in a generic way (be it generated or DynamicStructure). However if you want nicer API to work with the nodes etc., generation is still useful.

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 267

Currently Online:
12 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

hbrackel: 93

pramanj: 86

ibrahim: 69

kapsl: 57

gjevremovic: 49

TimK: 41

Fransua33: 39

fred: 36

Rainer Versteeg: 32

Thomas Reuther: 26

Member Stats:

Guest Posters: 0

Members: 990

Moderators: 13

Admins: 1

Forum Stats:

Groups: 3

Forums: 14

Topics: 945

Posts: 3987

Newest Members:

jerrodharness1, chandrahollis, kandimilano0008, deonbracewell, swati kulha, muoipoupinel64, lannybroadway, 12315544121666, Joel Mariadasan, alfonsobarringto

Moderators: Jouni Aro: 837, Otso Palonen: 32, Tuomas Hiltunen: 5, janimakela: 0, Pyry: 1, Terho: 0, Petri: 0, Bjarne Boström: 491, Heikki Tahvanainen: 402, Jukka Asikainen: 1, Teppo Uimonen: 18, Markus Johansson: 11, Matti Siponen: 8

Administrators: admin: 0