« All blog posts

Prosys OPC UA Java SDK 2.0 Release: Using Code Generated Classes

11.07.2014


We released version 2.0 of our OPC UA Java SDK earlier this week.

Feature Highlights

  • OPC Foundation Java Stack 1.02
  • HTTPS protocol
  • New SecurityPolicy: Basic256Sha256
  • More flexible security library usage (Bouncy Castle/Spongy Castle(for Android)/Sun JCE)
  • Standard OPC UA types as (generated) Java classes both on the client and server side
  • Option to use types for companion specifications (DI, ADI, PLCopen)
  • Code generator for enabling usage of custom types, both on the server and client side
  • Support for OPC UA File Transfer (FileType)
  • Enables disabling SecurityMode.None in the server
  • Enables disabling the internal discovery server
  • Enables binding the server to network interfaces independent of the EndpointUrls

OPC UA 1.02 features are explained in a previous blog post.

Full release notes can be found here. The focus of this blog post is on using the code generated classes because it is now the only way to create standard UA types in the server and they can also be used in the client side to make working with the nodes easier. It is also the main reason why the release took so long. Converting the SDK to use code-generated classes internally was not easy, but it also serverd as a quick feedback loop to improve the code-generator to produce classes that are good enough to be useful.

Code generation

Code generation is a major new feature in 2.0. Some of this has been shown in a previous blog post. The generator generates 5 class files for a given UA type: 1 interface and 4 classes. They are named the following way:

  • xxxType, interface, e.g. AnalogItemType
  • xxxTypeImplBase, client side base implementation of the interface (abstract class)
  • xxxTypeNodeBase, server side abstract base implementation (abstract class)
  • xxxTypeImpl, client side actual implementation
  • xxxTypeNode, server side actual implementation, implementation of UA methods

Idea is that the interface and the Base classes are always generated (e.g. they do not go to version control systems) and the Impl and Node classes can contain hand-written code, e.g. the implementations of UA methods and any convenience methods. The classes have same hierarchy as in the UA types. The standard types can be found in the following packages:

  • com.prosysopc.ua.types.opcua
  • com.prosysopc.ua.types.opcua.client
  • com.prosysopc.ua.types.opcua.server

The SDK also has classes for companion specifications (DI, ADI, PLCopen), they can be found in similar packages (replace opcua with di/adi/plc). Note however that these classes are just code-generated, therefore e.g. DI classes do not have any UA method implementations.

Using code generated classes on the client side

On the client side the interface should be used, because the SDK client-side implementations do not add any convenience methods to the interface. The AddressSpace.getNode(NodeId) method has been overloaded with one taking a Class parameter. Therefore you can now call:

AnalogItemType node = client.getAddressSpace().getNode(NodeId,
			AnalogItemType.class);

You can then use the node to get it’s properties:

//returns the InstrumentRange UaProperty

UaProperty property = node.getInstrumentRangeNode(); 

//direct return for the value of the InstrumentRange Property

Range instrumentRange = node.getInstrumentRange(); 

In the above example, the getInstrumentRangeNode() can return null, if the server side Node does not have an InstrumentRange Property. This can happen because the InstrumentRange is an Optional Property in the UA Specification. The methods in the generated classes have an @Optional annotation, if the Node is defined as Optional. They can also have a @Mandatory annotation indicating that the return value should not be null (but it can be null if the server does not follow the UA Specification). The value returned by getInstrumentRange can be null, firstly if the InstrumentRange Node does not exist and secondly if the actual value is null.

The Client side nodes do have a property value setter method similar to getter, but it should be noted here that that is for SDK’s internal use, i.e. calling the setter will not write the value to the server. Writing values must still be done using UaClient.write() methods.

Using code generated classes on server side

The SDK uses now the code-generated classes internally. The old standard type nodes from package com.prosysopc.ua.server.nodes.opcua are removed because they are not directly compatible: some interfaces are now supporting code-generated nodes and they can only support one class a time.

On the server side it is better to use the actual implementation class, `xxxTypeNode’, because some operations shouldn’t fail on the server side. Therefore methods in the actual implementation do not throw ServiceException and setting values do not throw StatusExceptions. Also the classes do have some convenience methods.

The most visible change is that the generated classes cannot be instantiated directly. This is because each generated class knows only one step of their structure and the Nodes do not store their own structure. Therefore the generated nodes must be instantiated using a NodeBuilder or using NodeManagerUaNode.createInstance(...) (which uses a NodeBuilder internally). The following lines show an examples of instantiating an AnalogItemType

// 1

AnalogItemType node = nodeManagerUaNode.createInstance(
	AnalogItemType.class, "AnalogItem");

// 2

AnalogItemTypeNode node = nodeManagerUaNode.createInstance(
	AnalogItemTypeNode.class, nodeId, browseName, displayName);

// 3

NodeBuilder<AnalogItemType> nb = nodeManagerUaNode.createNodeBuilder(AnalogItemType.class);
	AnalogItemType node = nb.setNodeId(...)
				.setBrowseName(...)
				.setDisplayName(...)
				.build();

In each of those examples, the new AnalogItemType node is also added to the NodeManagerUaNode.

The default instantiation of generated classed do not instantiate Optional InstanceDeclarations (UaObject/UaVariable instances in type definitions). This means that, for example, AnalogItemType by default does not have an InstrumentRange Property. These can be configured using UaNodeBuilderConfiguration, which is an interface for configuring a NodeBuilder. The SDK has one implementation, NodeBuilderConfiguration, which enables defining which Optionals to instantiate using NodeIds, ExpandedNodeIds and BrowsePaths. In addition to defining which Optionals to instantiate, the UaNodeBuilderConfiguration also defines how exactly the nodes should be instantiated. More on that subject on a later blog post. The following example explains how to use the NodeBuilderConfiguration (from our SampleConsoleServer):

// Configure the optional nodes using a NodeBuilderConfiguration

NodeBuilderConfiguration conf = new NodeBuilderConfiguration();

// You can use NodeIds to define Optional nodes (good for standard UA

// nodes as they always have namespace index of 0)

conf.addOptional(Identifiers.AnalogItemType_EngineeringUnits);

// You can also use ExpandedNodeIds with NamespaceUris if you don't know

// the namespace index.

conf.addOptional(new ExpandedNodeId(NamespaceTable.OPCUA_NAMESPACE,
		Identifiers.AnalogItemType_InstrumentRange.getValue()));

// You can also use the BrowsePath from the type if you like (the type's

// BrowseName is not included in the path, so this configuration will

// apply to any type which has the same path)

// You can use Strings for 0 namespace index, QualifiedNames for 1-step

// paths and BrowsePaths for full paths

// Each type interface has constants for it's structure (1-step deep)

conf.addOptional(AnalogItemType.DEFINITION);

// Use the NodeBuilder to create the node

final AnalogItemType node = complianceNodeManager
		.createNodeBuilder(AnalogItemType.class, conf)
		.setName(dataTypeName + "AnalogItem").build();

Summary

The code-generation and generated standard UA types are a major feature in 2.0. On the client side it allows easier access to sub-structures of a node of known type. On the server side it changes how the nodes are instantiated manually but opens up options in configuring how the nodes are instantiated. The instantiation process is quite complex and is one reason why the 2.0 release took so long.

Bjarne Boström profile photo

Bjarne Boström

Software Engineer

Email: bjarne.bostrom@prosysopc.com

Expertise and responsibility areas: OPC UA product development and project work

Tags: OPC UA, Java, Information Models, SDK for Java

comments powered by Disqus

About Prosys OPC Ltd

Prosys OPC is a leading provider of professional OPC software and services with over 20 years of experience in the field. OPC and OPC UA (Unified Architecture) are communications standards used especially by industrial and high-tech companies.

Read more about us »

Newest blog posts

Why Do Standards Matter in Smart Manufacturing?

The blog post discusses the importance of standards in smart manufacturing, envisioning a future where auto-configurable systems in manufacturing rely on standardized data formats for seamless integration and reduced costs, with a focus on the OPC UA standard family as a key enabler.

OPC UA PubSub to Cloud via MQTT

Detailed overview of the demo presented at the OPC Foundation booth

SimServer How To #3: Simulate data changes on a server using an OPC UA client

A two-part step-by-step tutorial on how to write data changes on an OPC UA server using an OPC UA client.

View all blog posts »