我们知道,opc ua 的节点,其value是有固定的数据类型的,即DataType
那么opc ua client向 opc ua server写入数据时,写入的值必须与server中的数据类型相匹配才能成功的写入进去。如果数据类型不匹配会抛出异常。
所以,我们需要获取opc ua server中节点的数据类型,通过将其与写入数据的数据类型进行对比,只有符合类型的才进行写入。
/*
* Copyright (c) 2019 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.opcua.stack.core;
import java.util.UUID;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
import org.eclipse.milo.opcua.stack.core.types.builtin.XmlElement;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
import org.eclipse.milo.opcua.stack.core.types.enumerated.IdType;
import org.eclipse.milo.opcua.stack.core.util.Namespaces;
import org.jetbrains.annotations.Nullable;
public enum BuiltinDataType {
Boolean(1, Boolean.class),
SByte(2, Byte.class),
Byte(3, UByte.class),
Int16(4, Short.class),
UInt16(5, UShort.class),
Int32(6, Integer.class),
UInt32(7, UInteger.class),
Int64(8, Long.class),
UInt64(9, ULong.class),
Float(10, Float.class),
Double(11, Double.class),
String(12, String.class),
DateTime(13, DateTime.class),
Guid(14, UUID.class),
ByteString(15, ByteString.class),
XmlElement(16, XmlElement.class),
NodeId(17, NodeId.class),
ExpandedNodeId(18, org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId.class),
StatusCode(19, StatusCode.class),
QualifiedName(20, QualifiedName.class),
LocalizedText(21, org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText.class),
ExtensionObject(22, ExtensionObject.class),
DataValue(23, org.eclipse.milo.opcua.stack.core.types.builtin.DataValue.class),
Variant(24, Variant.class),
DiagnosticInfo(25, org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo.class);
private final int typeId;
private final Class<?> backingClass;
BuiltinDataType(int typeId, Class<?> backingClass) {
this.typeId = typeId;
this.backingClass = backingClass;
}
public NodeId getNodeId() {
return new NodeId(0, typeId);
}
public int getTypeId() {
return typeId;
}
public Class<?> getBackingClass() {
return backingClass;
}
private static final BiMap<Integer, Class<?>> BackingClassesById;
private static final BiMap<NodeId, Class<?>> BackingClassesByNodeId;
private static final BiMap<NodeId, BuiltinDataType> DataTypesByNodeId;
static {
ImmutableBiMap.Builder<Integer, Class<?>> builder = ImmutableBiMap.builder();
ImmutableBiMap.Builder<NodeId, Class<?>> builder2 = ImmutableBiMap.builder();
ImmutableBiMap.Builder<NodeId, BuiltinDataType> builder3 = ImmutableBiMap.builder();
for (BuiltinDataType dataType : values()) {
builder.put(dataType.getTypeId(), dataType.getBackingClass());
builder2.put(dataType.getNodeId(), dataType.getBackingClass());
builder3.put(dataType.getNodeId(), dataType);
}
BackingClassesById = builder.build();
BackingClassesByNodeId = builder2.build();
DataTypesByNodeId = builder3.build();
}
/**
* @param backingClass the backing {@link Class} of the builtin type.
* @return the id of the builtin type backed by {@code backingClass}.
*/
public static int getBuiltinTypeId(Class<?> backingClass) {
return BackingClassesById.inverse().get(maybeBoxPrimitive(backingClass));
}
/**
* @param typeId the id of the builtin type.
* @return the {@link Class} backing the builtin type.
*/
@Nullable
public static Class<?> getBackingClass(int typeId) {
return BackingClassesById.get(typeId);
}
@Nullable
public static Class<?> getBackingClass(NodeId typeId) {
return BackingClassesByNodeId.get(typeId);
}
@Nullable
public static Class<?> getBackingClass(ExpandedNodeId typeId) {
if (typeId.getNamespaceIndex().intValue() == 0 && typeId.getType() == IdType.Numeric) {
Number id = (Number) typeId.getIdentifier();
return BackingClassesById.get(id.intValue());
}
return null;
}
@Nullable
public static BuiltinDataType fromBackingClass(Class<?> backingClass) {
NodeId nodeId = BackingClassesByNodeId.inverse().get(maybeBoxPrimitive(backingClass));
return nodeId != null ? DataTypesByNodeId.get(nodeId) : null;
}
@Nullable
public static BuiltinDataType fromNodeId(NodeId nodeId) {
return DataTypesByNodeId.get(nodeId);
}
@Nullable
public static BuiltinDataType fromNodeId(ExpandedNodeId nodeId) {
if (nodeId.getIdentifier() instanceof UInteger &&
(Namespaces.OPC_UA.equals(nodeId.getNamespaceUri()) || nodeId.getNamespaceIndex().intValue() == 0)) {
return fromNodeId(new NodeId(0, (UInteger) nodeId.getIdentifier()));
} else {
return null;
}
}
public static boolean isBuiltin(int typeId) {
return BackingClassesById.containsKey(typeId);
}
public static boolean isBuiltin(NodeId typeId) {
return BackingClassesByNodeId.containsKey(typeId);
}
public static boolean isBuiltin(ExpandedNodeId typeId) {
return BuiltinDataType.fromNodeId(typeId) != null;
}
private static Class<?> maybeBoxPrimitive(Class<?> clazz) {
if (clazz.isPrimitive()) {
if (clazz == boolean.class) {
return Boolean.class;
} else if (clazz == byte.class) {
return Byte.class;
} else if (clazz == short.class) {
return Short.class;
} else if (clazz == int.class) {
return Integer.class;
} else if (clazz == long.class) {
return Long.class;
} else if (clazz == float.class) {
return Float.class;
} else if (clazz == double.class) {
return Double.class;
}
}
return clazz;
}
}
NodeId serverNode = opcUaClient.getAddressSpace().getVariableNode(nodeId).getDataType();
BuiltinDataType type = BuiltinDataType.fromNodeId(serverNode);
type.toString()或者type.name就是诸如String,Integer,Boolean这些字符串。
下面是比较写入值和服务器节点类型的方法:
public static Boolean checkDataType(OpcUaClient opcUaClient, NodeId nodeId, Object value) throws UaException {
NodeId serverNode = opcUaClient.getAddressSpace().getVariableNode(nodeId).getDataType();
BuiltinDataType type = BuiltinDataType.fromNodeId(serverNode);
if (type != null) {
return value.getClass().getSimpleName().equals(type.toString());
}
return false;
}