Files
opcua-server/src/main/java/de/opcua/app/model/ExportNode.java
2026-05-10 14:17:32 +02:00

98 lines
4.0 KiB
Java

package de.opcua.app.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
/**
* Ein Knoten im OPC UA JSON-Export.
* Felder entsprechen dem opcua-export.json Format.
* referenceTypeId ist optional (z.B. "i=35", "i=46", "i=47").
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ExportNode {
public String name;
public String id;
public String browseName;
public String nodeClass;
public String dataType;
public String accessLevel;
public String value;
public String nodeId; // Feld im opcua-export Format
public String displayName; // Feld im opcua-export Format
public String referenceType; // z.B. "Organizes", "HasProperty", "HasComponent"
public String referenceTypeId; // z.B. "i=35" (Organizes), "i=46" (HasProperty), "i=47" (HasComponent)
public Boolean containsNoLoops; // OPC UA View-Attribut (null = unbekannt)
public Long viewVersion; // OPC UA View-Attribut UInt32 (null = unbekannt)
public List<ExportNode> children;
/** Effektiver Anzeigename: displayName > name > browseName. */
public String effectiveName() {
if (displayName != null && !displayName.isBlank()) return displayName;
if (name != null && !name.isBlank()) return name;
if (browseName != null && !browseName.isBlank()) return browseName;
return "Node";
}
/** Effektive NodeId: nodeId > id. */
public String effectiveNodeId() {
if (nodeId != null && !nodeId.isBlank()) return nodeId;
return id;
}
public String effectiveDataType() { return dataType; }
public boolean isVariable() {
if (nodeClass != null)
return "Variable".equals(nodeClass) || "VariableType".equals(nodeClass);
return value != null || dataType != null;
}
private static String referenceTypeToId(String ref) {
if (ref == null || ref.isBlank()) return null;
return switch (ref) {
case "Organizes" -> "i=35";
case "HasTypeDefinition" -> "i=40";
case "HasSubtype" -> "i=45";
case "HasProperty" -> "i=46";
case "HasComponent" -> "i=47";
case "HasNotifier" -> "i=48";
default -> ref;
};
}
/** Konvertiert zu TreeNodeRef für GUI. */
public TreeNodeRef toTreeNodeRef() {
// 9-Arg-Konstruktor: alle Felder inkl. View-Attribute
return new TreeNodeRef(
effectiveName(),
effectiveNodeId(),
browseName != null ? browseName : effectiveName(),
nodeClass != null ? nodeClass : (isVariable() ? "Variable" : "Object"),
dataType,
accessLevel != null ? accessLevel : "ReadWrite",
referenceTypeId != null ? referenceTypeId : referenceTypeToId(referenceType),
containsNoLoops != null ? containsNoLoops : true, // Default: true (sicher)
viewVersion != null ? viewVersion : 0L // Default: 0 (unversioniert)
);
}
/** Konvertiert TreeNodeRef-Daten zurück in ExportNode. */
public static ExportNode fromTreeNodeRef(TreeNodeRef ref) {
ExportNode en = new ExportNode();
en.name = ref.displayName();
en.id = ref.nodeId();
en.nodeId = ref.nodeId();
en.displayName = ref.displayName();
en.browseName = ref.browseName();
en.nodeClass = ref.nodeClass();
en.dataType = ref.dataType();
en.accessLevel = ref.accessLevel();
en.referenceTypeId = ref.referenceTypeId();
en.referenceType = ref.referenceTypeId() != null ? TreeNodeRef.resolveRefTypeId(ref.referenceTypeId()) : null;
en.containsNoLoops = ref.containsNoLoops();
en.viewVersion = ref.viewVersion();
return en;
}
}