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 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; } }