Skip to content

Commit

Permalink
~ Union example and support in dictionary generator
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinherron committed Jan 20, 2020
1 parent 5df02d0 commit a8a79d0
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.milo.examples.server.methods.SqrtMethod;
import org.eclipse.milo.examples.server.types.CustomDataType;
import org.eclipse.milo.examples.server.types.CustomEnumType;
import org.eclipse.milo.examples.server.types.CustomUnionType;
import org.eclipse.milo.opcua.sdk.core.AccessLevel;
import org.eclipse.milo.opcua.sdk.core.Reference;
import org.eclipse.milo.opcua.sdk.core.ValueRank;
Expand Down Expand Up @@ -188,6 +189,13 @@ protected void onStartup() {
logger.warn("Failed to register custom struct type", e);
}

try {
registerCustomUnionType();
addCustomUnionVariable(folderNode);
} catch (Exception e) {
logger.warn("Failed to register custom struct type", e);
}

addCustomObjectTypeAndInstance(folderNode);

// Set the EventNotifier bit on Server Node for Events.
Expand Down Expand Up @@ -815,6 +823,57 @@ private void registerCustomStructType() throws Exception {
dictionaryManager.registerStructureDescription(description, binaryEncodingId);
}

private void registerCustomUnionType() throws Exception {
NodeId dataTypeId = CustomUnionType.TYPE_ID
.localOrThrow(getServer().getNamespaceTable());

NodeId binaryEncodingId = CustomUnionType.BINARY_ENCODING_ID
.localOrThrow(getServer().getNamespaceTable());

dictionaryManager.registerStructureCodec(
new CustomUnionType.Codec().asBinaryCodec(),
"CustomUnionType",
dataTypeId,
binaryEncodingId
);

StructureField[] fields = new StructureField[]{
new StructureField(
"foo",
LocalizedText.NULL_VALUE,
Identifiers.UInt32,
ValueRanks.Scalar,
null,
getServer().getConfig().getLimits().getMaxStringLength(),
false
),
new StructureField(
"bar",
LocalizedText.NULL_VALUE,
Identifiers.String,
ValueRanks.Scalar,
null,
uint(0),
false
)
};

StructureDefinition definition = new StructureDefinition(
binaryEncodingId,
Identifiers.Structure,
StructureType.Union,
fields
);

StructureDescription description = new StructureDescription(
dataTypeId,
new QualifiedName(getNamespaceIndex(), "CustomUnionType"),
definition
);

dictionaryManager.registerStructureDescription(description, binaryEncodingId);
}

private void addCustomEnumVariable(UaFolderNode rootFolder) throws Exception {
NodeId dataTypeId = CustomEnumType.TYPE_ID
.localOrThrow(getServer().getNamespaceTable());
Expand Down Expand Up @@ -882,6 +941,43 @@ private void addCustomStructVariable(UaFolderNode rootFolder) throws Exception {
));
}

private void addCustomUnionVariable(UaFolderNode rootFolder) throws Exception {
NodeId dataTypeId = CustomUnionType.TYPE_ID
.localOrThrow(getServer().getNamespaceTable());

NodeId binaryEncodingId = CustomUnionType.BINARY_ENCODING_ID
.localOrThrow(getServer().getNamespaceTable());

UaVariableNode customUnionTypeVariable = UaVariableNode.builder(getNodeContext())
.setNodeId(newNodeId("HelloWorld/CustomUnionTypeVariable"))
.setAccessLevel(ubyte(AccessLevel.getMask(AccessLevel.READ_WRITE)))
.setUserAccessLevel(ubyte(AccessLevel.getMask(AccessLevel.READ_WRITE)))
.setBrowseName(newQualifiedName("CustomUnionTypeVariable"))
.setDisplayName(LocalizedText.english("CustomUnionTypeVariable"))
.setDataType(dataTypeId)
.setTypeDefinition(Identifiers.BaseDataVariableType)
.build();

CustomUnionType value = CustomUnionType.ofBar("hello");

ExtensionObject xo = ExtensionObject.encodeDefaultBinary(
getServer().getSerializationContext(),
value,
binaryEncodingId
);

customUnionTypeVariable.setValue(new DataValue(new Variant(xo)));

getNodeManager().addNode(customUnionTypeVariable);

customUnionTypeVariable.addReference(new Reference(
customUnionTypeVariable.getNodeId(),
Identifiers.Organizes,
rootFolder.getNodeId().expanded(),
false
));
}

@Override
public void onDataItemsCreated(List<DataItem> dataItems) {
subscriptionModel.onDataItemsCreated(dataItems);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2020 the Eclipse Milo Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/

package org.eclipse.milo.examples.server.types;

import org.eclipse.milo.examples.server.ExampleNamespace;
import org.eclipse.milo.opcua.stack.core.StatusCodes;
import org.eclipse.milo.opcua.stack.core.UaSerializationException;
import org.eclipse.milo.opcua.stack.core.serialization.SerializationContext;
import org.eclipse.milo.opcua.stack.core.serialization.UaDecoder;
import org.eclipse.milo.opcua.stack.core.serialization.UaEncoder;
import org.eclipse.milo.opcua.stack.core.serialization.UaStructure;
import org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.structured.Union;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;

public class CustomUnionType extends Union implements UaStructure {

public static final ExpandedNodeId TYPE_ID = ExpandedNodeId.parse(String.format(
"nsu=%s;s=%s",
ExampleNamespace.NAMESPACE_URI,
"DataType.CustomUnionType"
));

public static final ExpandedNodeId BINARY_ENCODING_ID = ExpandedNodeId.parse(String.format(
"nsu=%s;s=%s",
ExampleNamespace.NAMESPACE_URI,
"DataType.CustomUnionType.BinaryEncoding"
));

private final Type type;
private final Object value;

private CustomUnionType(Type type, Object value) {
this.type = type;
this.value = value;
}

@Override
public ExpandedNodeId getTypeId() {
return TYPE_ID;
}

@Override
public ExpandedNodeId getBinaryEncodingId() {
return BINARY_ENCODING_ID;
}

@Override
public ExpandedNodeId getXmlEncodingId() {
// XML encoding not supported
return ExpandedNodeId.NULL_VALUE;
}

public UInteger asFoo() {
return (UInteger) value;
}

public String asBar() {
return (String) value;
}

public boolean isNull() {
return type == Type.Null;
}

public boolean isFoo() {
return type == Type.Foo;
}

public boolean isBar() {
return type == Type.Bar;
}

public static CustomUnionType ofNull() {
return new CustomUnionType(Type.Null, null);
}

public static CustomUnionType ofFoo(UInteger value) {
return new CustomUnionType(Type.Foo, value);
}

public static CustomUnionType ofBar(String value) {
return new CustomUnionType(Type.Bar, value);
}

enum Type {
Null,
Foo,
Bar
}

public static class Codec extends GenericDataTypeCodec<CustomUnionType> {
@Override
public Class<CustomUnionType> getType() {
return CustomUnionType.class;
}

@Override
public CustomUnionType decode(SerializationContext context, UaDecoder decoder) {
UInteger switchValue = decoder.readUInt32("SwitchValue");
switch (switchValue.intValue()) {
case 0:
return CustomUnionType.ofNull();
case 1: {
UInteger foo = decoder.readUInt32("foo");
return CustomUnionType.ofFoo(foo);
}
case 2: {
String bar = decoder.readString("bar");
return CustomUnionType.ofBar(bar);
}
default:
throw new UaSerializationException(
StatusCodes.Bad_DecodingError,
"unknown field in Union CustomUnionType: " + switchValue
);
}
}

@Override
public void encode(SerializationContext context, UaEncoder encoder, CustomUnionType value) {
encoder.writeUInt32("SwitchValue", uint(value.type.ordinal()));
switch (value.type) {
case Null:
break;
case Foo: {
encoder.writeUInt32("foo", value.asFoo());
}
case Bar: {
encoder.writeString("bar", value.asBar());
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,6 @@ public void addEnumDescription(EnumDescription description) {
}

public void addStructureDescription(StructureDescription description) {
StructureType structureType = description.getStructureDefinition().getStructureType();

if (structureType == StructureType.Union) {
throw new IllegalArgumentException("StructureType not supported: " + structureType);
}

structuredTypes.add(createStructuredType(description));

structureDescriptions.put(description.getDataTypeId(), description);
Expand Down

0 comments on commit a8a79d0

Please sign in to comment.