diff --git a/src/main/java/com/beanit/iec61850bean/ConnectionParam.java b/src/main/java/com/beanit/iec61850bean/ConnectionParam.java new file mode 100644 index 0000000..0e25626 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ConnectionParam.java @@ -0,0 +1,148 @@ +package com.beanit.iec61850bean; + +import java.util.Objects; + +public class ConnectionParam { + private String iedName; + + private String IP; + private String IP_SUBNET; + private String OSI_AP_Title; + private String OSI_AE_Qualifier; + private String OSI_PSEL; + private String OSI_SSEL; + private String OSI_TSEL; + private String IP_GATEWAY; + private String S_Profile; + private String MAC_Address; + + + public String getIedName() { + return iedName; + } + + public void setIedName(String iedName) { + this.iedName = iedName; + } + + public String getIP() { + return IP; + } + + public void setIP(String IP) { + this.IP = IP; + } + + public String getIP_SUBNET() { + return IP_SUBNET; + } + + public void setIP_SUBNET(String IP_SUBNET) { + this.IP_SUBNET = IP_SUBNET; + } + + public String getOSI_AP_Title() { + return OSI_AP_Title; + } + + public void setOSI_AP_Title(String OSI_AP_Title) { + this.OSI_AP_Title = OSI_AP_Title; + } + + public String getOSI_AE_Qualifier() { + return OSI_AE_Qualifier; + } + + public void setOSI_AE_Qualifier(String OSI_AE_Qualifier) { + this.OSI_AE_Qualifier = OSI_AE_Qualifier; + } + + public String getOSI_PSEL() { + return OSI_PSEL; + } + + public void setOSI_PSEL(String OSI_PSEL) { + this.OSI_PSEL = OSI_PSEL; + } + + public String getOSI_SSEL() { + return OSI_SSEL; + } + + public void setOSI_SSEL(String OSI_SSEL) { + this.OSI_SSEL = OSI_SSEL; + } + + public String getOSI_TSEL() { + return OSI_TSEL; + } + + public void setOSI_TSEL(String OSI_TSEL) { + this.OSI_TSEL = OSI_TSEL; + } + + public String getIP_GATEWAY() { + return IP_GATEWAY; + } + + public void setIP_GATEWAY(String IP_GATEWAY) { + this.IP_GATEWAY = IP_GATEWAY; + } + + public String getS_Profile() { + return S_Profile; + } + + public void setS_Profile(String s_Profile) { + S_Profile = s_Profile; + } + + public String getMAC_Address() { + return MAC_Address; + } + + public void setMAC_Address(String MAC_Address) { + this.MAC_Address = MAC_Address; + } + + + @Override + public String toString() { + return "iedName = " + iedName + '\n' + + "IP = " + IP + '\n' + + "IP_SUBNET = " + IP_SUBNET + '\n' + + "OSI_AP_Title = " + OSI_AP_Title + '\n' + + "OSI_AE_Qualifier = " + OSI_AE_Qualifier + '\n' + + "OSI_PSEL = " + OSI_PSEL + '\n' + + "OSI_SSEL = " + OSI_SSEL + '\n' + + "OSI_TSEL = " + OSI_TSEL + '\n' + + "IP_GATEWAY = " + IP_GATEWAY + '\n' + + "S_Profile = " + S_Profile + '\n' + + "MAC-Address = " + MAC_Address + ; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConnectionParam that = (ConnectionParam) o; + return iedName.equals(that.iedName) && + IP.equals(that.IP) && + Objects.equals(IP_SUBNET, that.IP_SUBNET) && + Objects.equals(OSI_AP_Title, that.OSI_AP_Title) && + Objects.equals(OSI_AE_Qualifier, that.OSI_AE_Qualifier) && + Objects.equals(OSI_PSEL, that.OSI_PSEL) && + Objects.equals(OSI_SSEL, that.OSI_SSEL) && + Objects.equals(OSI_TSEL, that.OSI_TSEL) && + Objects.equals(IP_GATEWAY, that.IP_GATEWAY) && + Objects.equals(S_Profile, that.S_Profile) && + Objects.equals(MAC_Address, that.MAC_Address); + } + + @Override + public int hashCode() { + return Objects.hash(iedName, IP, IP_SUBNET, OSI_AP_Title, OSI_AE_Qualifier, OSI_PSEL, OSI_SSEL, + OSI_TSEL, IP_GATEWAY, S_Profile, MAC_Address); + } +} \ No newline at end of file diff --git a/src/main/java/com/beanit/iec61850bean/SclParser.java b/src/main/java/com/beanit/iec61850bean/SclParser.java index adc5a10..d917443 100644 --- a/src/main/java/com/beanit/iec61850bean/SclParser.java +++ b/src/main/java/com/beanit/iec61850bean/SclParser.java @@ -1,3 +1,4 @@ + /* * Copyright 2011 The IEC61850bean Authors * @@ -13,1098 +14,1180 @@ */ package com.beanit.iec61850bean; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.beanit.iec61850bean.internal.scl.AbstractDataAttribute; -import com.beanit.iec61850bean.internal.scl.Bda; -import com.beanit.iec61850bean.internal.scl.Da; -import com.beanit.iec61850bean.internal.scl.DaType; -import com.beanit.iec61850bean.internal.scl.Do; -import com.beanit.iec61850bean.internal.scl.DoType; -import com.beanit.iec61850bean.internal.scl.EnumType; -import com.beanit.iec61850bean.internal.scl.EnumVal; -import com.beanit.iec61850bean.internal.scl.LnSubDef; -import com.beanit.iec61850bean.internal.scl.LnType; -import com.beanit.iec61850bean.internal.scl.Sdo; -import com.beanit.iec61850bean.internal.scl.TypeDefinitions; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import javax.xml.parsers.DocumentBuilderFactory; +import com.beanit.iec61850bean.internal.scl.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -public class SclParser { - - private final Map dataSetsMap = new HashMap<>(); - private final List dataSetDefs = new ArrayList<>(); - private TypeDefinitions typeDefinitions; - private Document doc; - private String iedName; - private List serverModels = new ArrayList<>(); - private boolean useResvTmsAttributes = false; - - private SclParser() {} - - public static List parse(InputStream is) throws SclParseException { - SclParser sclParser = new SclParser(); - sclParser.parseStream(is); - return sclParser.serverModels; - } - - public static List parse(String sclFilePath) throws SclParseException { - try { - return parse(new FileInputStream(sclFilePath)); - } catch (FileNotFoundException e) { - throw new SclParseException(e); - } - } - - private void parseStream(InputStream icdFileStream) throws SclParseException { +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.*; - typeDefinitions = new TypeDefinitions(); +import static java.nio.charset.StandardCharsets.UTF_8; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setIgnoringComments(true); +public class SclParser { - try { - doc = factory.newDocumentBuilder().parse(icdFileStream); - } catch (Exception e) { - throw new SclParseException(e); - } + private final Map dataSetsMap = new HashMap<>(); + private final List dataSetDefs = new ArrayList<>(); + private TypeDefinitions typeDefinitions; + private Document doc; + private String iedName; + private final List serverModels = new ArrayList<>(); + private boolean useResvTmsAttributes = false; - Node rootNode = doc.getDocumentElement(); + ConnectionParam connectionParm; + private final Map iedConnectionMap = new HashMap<>(); - if (!"SCL".equals(rootNode.getNodeName())) { - throw new SclParseException("Root node in SCL file is not of type \"SCL\""); + private SclParser() { } - readTypeDefinitions(); - - NodeList iedList = doc.getElementsByTagName("IED"); - if (iedList.getLength() == 0) { - throw new SclParseException("No IED section found!"); + public static List parse(InputStream is) throws SclParseException { + SclParser sclParser = new SclParser(); + sclParser.parseStream(is); + return sclParser.serverModels; } - for (int z = 0; z < iedList.getLength(); z++) { - Node iedNode = iedList.item(z); - - useResvTmsAttributes = false; - - Node nameAttribute = iedNode.getAttributes().getNamedItem("name"); - - iedName = nameAttribute.getNodeValue(); - if ((iedName == null) || (iedName.length() == 0)) { - throw new SclParseException("IED must have a name!"); - } - - NodeList iedElements = iedNode.getChildNodes(); - - for (int i = 0; i < iedElements.getLength(); i++) { - Node element = iedElements.item(i); - String nodeName = element.getNodeName(); - if ("AccessPoint".equals(nodeName)) { - ServerSap serverSap = createAccessPoint(element); - if (serverSap != null) { - serverModels.add(serverSap.serverModel); - } - } else if ("Services".equals(nodeName)) { - NodeList servicesElements = element.getChildNodes(); - for (int j = 0; j < servicesElements.getLength(); j++) { - if ("ReportSettings".equals(servicesElements.item(j).getNodeName())) { - Node resvTmsAttribute = - servicesElements.item(j).getAttributes().getNamedItem("resvTms"); - if (resvTmsAttribute != null) { - useResvTmsAttributes = resvTmsAttribute.getNodeValue().equalsIgnoreCase("true"); - } - } - } + public static List parse(String sclFilePath) throws SclParseException { + try { + return parse(new FileInputStream(sclFilePath)); + } catch (FileNotFoundException e) { + throw new SclParseException(e); } - } } - } - private void readTypeDefinitions() throws SclParseException { + private void parseStream(InputStream icdFileStream) throws SclParseException { - NodeList dttSections = doc.getElementsByTagName("DataTypeTemplates"); + typeDefinitions = new TypeDefinitions(); - if (dttSections.getLength() != 1) { - throw new SclParseException("Only one DataTypeSection allowed"); - } + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setIgnoringComments(true); - Node dtt = dttSections.item(0); + try { + doc = factory.newDocumentBuilder().parse(icdFileStream); + } catch (Exception e) { + throw new SclParseException(e); + } - NodeList dataTypes = dtt.getChildNodes(); + Node rootNode = doc.getDocumentElement(); - for (int i = 0; i < dataTypes.getLength(); i++) { - Node element = dataTypes.item(i); + if (!"SCL".equals(rootNode.getNodeName())) { + throw new SclParseException("Root node in SCL file is not of type \"SCL\""); + } - String nodeName = element.getNodeName(); + readTypeDefinitions(); - if (nodeName.equals("LNodeType")) { - typeDefinitions.putLNodeType(new LnType(element)); - } else if (nodeName.equals("DOType")) { - typeDefinitions.putDOType(new DoType(element)); - } else if (nodeName.equals("DAType")) { - typeDefinitions.putDAType(new DaType(element)); - } else if (nodeName.equals("EnumType")) { - typeDefinitions.putEnumType(new EnumType(element)); - } - } - } + NodeList connectedAPs = doc.getElementsByTagName("ConnectedAP"); - private ServerSap createAccessPoint(Node iedServer) throws SclParseException { - ServerSap serverSap = null; + for (int zz = 0; zz < connectedAPs.getLength(); zz++) { + Node connectedAP = connectedAPs.item(zz); + Node attributeName = connectedAP.getAttributes().getNamedItem("iedName"); + String iedConnectedAP = attributeName.getNodeValue(); + connectionParm = new ConnectionParam(); + if ((iedConnectedAP == null) || (iedConnectedAP.length() == 0)) { + throw new SclParseException("ConnectedAP must has a name"); + } + NodeList elementsConnectedAP = connectedAP.getChildNodes(); + + for (int yy = 0; yy < elementsConnectedAP.getLength(); yy++) { + Node elementConnectedAP = elementsConnectedAP.item(yy); + String nodeAddress = elementConnectedAP.getNodeName(); + if (nodeAddress.equals("Address")) { + + NodeList address = elementConnectedAP.getChildNodes(); + for (int ii = 0; ii < address.getLength(); ii++) { + + Node elementAddress = address.item(ii); + + String nodeCheck = elementAddress.getNodeName(); + if ("P".equals(nodeCheck)) { + setConnectionParm(elementAddress); + } + } + connectionParm.setIedName(iedConnectedAP); + iedConnectionMap.put(iedConnectedAP, connectionParm); + } + } + } - NodeList elements = iedServer.getChildNodes(); + NodeList iedList = doc.getElementsByTagName("IED"); + if (iedList.getLength() == 0) { + throw new SclParseException("No IED section found!"); + } + + for (int z = 0; z < iedList.getLength(); z++) { + Node iedNode = iedList.item(z); - for (int i = 0; i < elements.getLength(); i++) { - Node element = elements.item(i); + useResvTmsAttributes = false; - if (element.getNodeName().equals("Server")) { + Node nameAttribute = iedNode.getAttributes().getNamedItem("name"); - ServerModel server = createServerModel(element); + iedName = nameAttribute.getNodeValue(); + if ((iedName == null) || (iedName.length() == 0)) { + throw new SclParseException("IED must have a name!"); + } - Node namedItem = iedServer.getAttributes().getNamedItem("name"); - if (namedItem == null) { - throw new SclParseException("AccessPoint has no name attribute!"); + NodeList iedElements = iedNode.getChildNodes(); + + for (int i = 0; i < iedElements.getLength(); i++) { + Node element = iedElements.item(i); + String nodeName = element.getNodeName(); + if ("AccessPoint".equals(nodeName)) { + ServerSap serverSap = createAccessPoint(element); + if (serverSap != null) { + serverModels.add(serverSap.serverModel); + } + } else if ("Services".equals(nodeName)) { + NodeList servicesElements = element.getChildNodes(); + for (int j = 0; j < servicesElements.getLength(); j++) { + if ("ReportSettings".equals(servicesElements.item(j).getNodeName())) { + Node resvTmsAttribute = + servicesElements.item(j).getAttributes().getNamedItem("resvTms"); + if (resvTmsAttribute != null) { + useResvTmsAttributes = resvTmsAttribute.getNodeValue().equalsIgnoreCase("true"); + } + } + } + } + } } - // TODO save this name? - serverSap = new ServerSap(102, 0, null, server, null); + } - break; - } + public void setConnectionParm(Node P) { + String nodeValue; + + P.getAttributes().getNamedItem("type"); + String typeValue = P.getAttributes().getNamedItem("type").getNodeValue(); + + nodeValue = P.getTextContent(); + + switch (typeValue) { + case "IP": + connectionParm.setIP(nodeValue); + break; + case "IP-SUBNET": + connectionParm.setIP_SUBNET(nodeValue); + break; + case "OSI-AP-Title": + connectionParm.setOSI_AP_Title(nodeValue); + break; + case "OSI-AE-Qualifier": + connectionParm.setOSI_AE_Qualifier(nodeValue); + break; + case "OSI-PSEL": + connectionParm.setOSI_PSEL(nodeValue); + break; + case "OSI-SSEL": + connectionParm.setOSI_SSEL(nodeValue); + break; + case "OSI-TSEL": + connectionParm.setOSI_TSEL(nodeValue); + break; + case "IP-GATEWAY": + connectionParm.setIP_GATEWAY(nodeValue); + break; + case "S-Profile": + connectionParm.setS_Profile(nodeValue); + break; + case "MAC-Address": + connectionParm.setMAC_Address(nodeValue); + break; + } } - return serverSap; - } + private void readTypeDefinitions() throws SclParseException { - private ServerModel createServerModel(Node serverXMLNode) throws SclParseException { + NodeList dttSections = doc.getElementsByTagName("DataTypeTemplates"); - NodeList elements = serverXMLNode.getChildNodes(); - List logicalDevices = new ArrayList<>(elements.getLength()); + if (dttSections.getLength() != 1) { + throw new SclParseException("Only one DataTypeSection allowed"); + } - for (int i = 0; i < elements.getLength(); i++) { - Node element = elements.item(i); + Node dtt = dttSections.item(0); - if (element.getNodeName().equals("LDevice")) { - logicalDevices.add(createNewLDevice(element)); - } - } + NodeList dataTypes = dtt.getChildNodes(); - ServerModel serverModel = new ServerModel(logicalDevices, null); + for (int i = 0; i < dataTypes.getLength(); i++) { + Node element = dataTypes.item(i); - dataSetsMap.clear(); + String nodeName = element.getNodeName(); - for (LnSubDef dataSetDef : dataSetDefs) { - DataSet dataSet = createDataSet(serverModel, dataSetDef.logicalNode, dataSetDef.defXmlNode); - dataSetsMap.put(dataSet.getReferenceStr(), dataSet); + switch (nodeName) { + case "LNodeType": + typeDefinitions.putLNodeType(new LnType(element)); + break; + case "DOType": + typeDefinitions.putDOType(new DoType(element)); + break; + case "DAType": + typeDefinitions.putDAType(new DaType(element)); + break; + case "EnumType": + typeDefinitions.putEnumType(new EnumType(element)); + break; + } + } } - serverModel.addDataSets(dataSetsMap.values()); - - dataSetDefs.clear(); + private ServerSap createAccessPoint(Node iedServer) throws SclParseException { + ServerSap serverSap = null; - return serverModel; - } + NodeList elements = iedServer.getChildNodes(); - private LogicalDevice createNewLDevice(Node ldXmlNode) throws SclParseException { + for (int i = 0; i < elements.getLength(); i++) { + Node element = elements.item(i); - String inst = null; - String ldName = null; + if (element.getNodeName().equals("Server")) { - NamedNodeMap attributes = ldXmlNode.getAttributes(); + ServerModel server = createServerModel(element); - for (int i = 0; i < attributes.getLength(); i++) { - Node node = attributes.item(i); - String nodeName = node.getNodeName(); + Node namedItem = iedServer.getAttributes().getNamedItem("name"); + if (namedItem == null) { + throw new SclParseException("AccessPoint has no name attribute!"); + } + // TODO save this name? + serverSap = new ServerSap(102, 0, null, server, null); - if (nodeName.equals("inst")) { - inst = node.getNodeValue(); - } else if (nodeName.equals("ldName")) { - ldName = node.getNodeValue(); - } - } + break; + } + } - if (inst == null) { - throw new SclParseException("Required attribute \"inst\" in logical device not found!"); + return serverSap; } - NodeList elements = ldXmlNode.getChildNodes(); - List logicalNodes = new ArrayList<>(); - - String ref; - if ((ldName != null) && (ldName.length() != 0)) { - ref = ldName; - } else { - ref = iedName + inst; - } + private ServerModel createServerModel(Node serverXMLNode) throws SclParseException { - for (int i = 0; i < elements.getLength(); i++) { - Node element = elements.item(i); + NodeList elements = serverXMLNode.getChildNodes(); + List logicalDevices = new ArrayList<>(elements.getLength()); - if (element.getNodeName().equals("LN") || element.getNodeName().equals("LN0")) { - logicalNodes.add(createNewLogicalNode(element, ref)); - } - } + for (int i = 0; i < elements.getLength(); i++) { + Node element = elements.item(i); - LogicalDevice lDevice = new LogicalDevice(new ObjectReference(ref), logicalNodes); + if (element.getNodeName().equals("LDevice")) { + logicalDevices.add(createNewLDevice(element)); + } + } - return lDevice; - } + ServerModel serverModel = new ServerModel(logicalDevices, null); - private LogicalNode createNewLogicalNode(Node lnXmlNode, String parentRef) - throws SclParseException { + dataSetsMap.clear(); - // attributes not needed: desc + for (LnSubDef dataSetDef : dataSetDefs) { + DataSet dataSet = createDataSet(serverModel, dataSetDef.logicalNode, dataSetDef.defXmlNode); + dataSetsMap.put(dataSet.getReferenceStr(), dataSet); + } - String inst = null; - String lnClass = null; - String lnType = null; - String prefix = ""; + serverModel.addDataSets(dataSetsMap.values()); - NamedNodeMap attributes = lnXmlNode.getAttributes(); + dataSetDefs.clear(); - for (int i = 0; i < attributes.getLength(); i++) { - Node node = attributes.item(i); - String nodeName = node.getNodeName(); + serverModel.setConnectionParam(iedConnectionMap.get(iedName)); - if (nodeName.equals("inst")) { - inst = node.getNodeValue(); - } else if (nodeName.equals("lnType")) { - lnType = node.getNodeValue(); - } else if (nodeName.equals("lnClass")) { - lnClass = node.getNodeValue(); - } else if (nodeName.equals("prefix")) { - prefix = node.getNodeValue(); - } + return serverModel; } - if (inst == null) { - throw new SclParseException("Required attribute \"inst\" not found!"); - } - if (lnType == null) { - throw new SclParseException("Required attribute \"lnType\" not found!"); - } - if (lnClass == null) { - throw new SclParseException("Required attribute \"lnClass\" not found!"); - } + private LogicalDevice createNewLDevice(Node ldXmlNode) throws SclParseException { - String ref = parentRef + '/' + prefix + lnClass + inst; + String inst = null; + String ldName = null; - LnType lnTypeDef = typeDefinitions.getLNodeType(lnType); + NamedNodeMap attributes = ldXmlNode.getAttributes(); - List dataObjects = new ArrayList<>(); + for (int i = 0; i < attributes.getLength(); i++) { + Node node = attributes.item(i); + String nodeName = node.getNodeName(); - if (lnTypeDef == null) { - throw new SclParseException("LNType " + lnType + " not defined!"); - } - for (Do dobject : lnTypeDef.dos) { - - // look for DOI node with the name of the DO - Node doiNodeFound = null; - for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { - Node childNode = lnXmlNode.getChildNodes().item(i); - if ("DOI".equals(childNode.getNodeName())) { - - NamedNodeMap doiAttributes = childNode.getAttributes(); - Node nameAttribute = doiAttributes.getNamedItem("name"); - if (nameAttribute != null && nameAttribute.getNodeValue().equals(dobject.getName())) { - doiNodeFound = childNode; - } + if (nodeName.equals("inst")) { + inst = node.getNodeValue(); + } else if (nodeName.equals("ldName")) { + ldName = node.getNodeValue(); + } } - } - dataObjects.addAll( - createFcDataObjects(dobject.getName(), ref, dobject.getType(), doiNodeFound)); - } + if (inst == null) { + throw new SclParseException("Required attribute \"inst\" in logical device not found!"); + } - // look for ReportControl - for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { - Node childNode = lnXmlNode.getChildNodes().item(i); - if ("ReportControl".equals(childNode.getNodeName())) { - dataObjects.addAll(createReportControlBlocks(childNode, ref)); - } - } + NodeList elements = ldXmlNode.getChildNodes(); + List logicalNodes = new ArrayList<>(); - LogicalNode lNode = new LogicalNode(new ObjectReference(ref), dataObjects); + String ref; + if ((ldName != null) && (ldName.length() != 0)) { + ref = ldName; + } else { + ref = iedName + inst; + } - // look for DataSet definitions - for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { - Node childNode = lnXmlNode.getChildNodes().item(i); - if ("DataSet".equals(childNode.getNodeName())) { - dataSetDefs.add(new LnSubDef(childNode, lNode)); - } - } - return lNode; - } + for (int i = 0; i < elements.getLength(); i++) { + Node element = elements.item(i); + + if (element.getNodeName().equals("LN") || element.getNodeName().equals("LN0")) { + logicalNodes.add(createNewLogicalNode(element, ref)); + } + } - private DataSet createDataSet(ServerModel serverModel, LogicalNode lNode, Node dsXmlNode) - throws SclParseException { + LogicalDevice lDevice = new LogicalDevice(new ObjectReference(ref), logicalNodes); - Node nameAttribute = dsXmlNode.getAttributes().getNamedItem("name"); - if (nameAttribute == null) { - throw new SclParseException("DataSet must have a name"); + return lDevice; } - String name = nameAttribute.getNodeValue(); + private LogicalNode createNewLogicalNode(Node lnXmlNode, String parentRef) + throws SclParseException { - List dsMembers = new ArrayList<>(); + // attributes not needed: desc - for (int i = 0; i < dsXmlNode.getChildNodes().getLength(); i++) { - Node fcdaXmlNode = dsXmlNode.getChildNodes().item(i); - if ("FCDA".equals(fcdaXmlNode.getNodeName())) { + String inst = null; + String lnClass = null; + String lnType = null; + String prefix = ""; - // For the definition of FCDA see Table 22 part6 ed2 + NamedNodeMap attributes = lnXmlNode.getAttributes(); - String ldInst = null; - String prefix = ""; - String lnClass = null; - String lnInst = ""; - String doName = ""; - String daName = ""; - Fc fc = null; - - NamedNodeMap attributes = fcdaXmlNode.getAttributes(); - - for (int j = 0; j < attributes.getLength(); j++) { - Node node = attributes.item(j); - String nodeName = node.getNodeName(); - - if (nodeName.equals("ldInst")) { - ldInst = node.getNodeValue(); - } else if (nodeName.equals("lnInst")) { - lnInst = node.getNodeValue(); - } else if (nodeName.equals("lnClass")) { - lnClass = node.getNodeValue(); - } else if (nodeName.equals("prefix")) { - prefix = node.getNodeValue(); - } else if (nodeName.equals("doName")) { - doName = node.getNodeValue(); - } else if (nodeName.equals("daName")) { - if (!node.getNodeValue().isEmpty()) { - daName = "." + node.getNodeValue(); - } - } else if (nodeName.equals("fc")) { - fc = Fc.fromString(node.getNodeValue()); - if (fc == null) { - throw new SclParseException("FCDA contains invalid FC: " + node.getNodeValue()); + for (int i = 0; i < attributes.getLength(); i++) { + Node node = attributes.item(i); + String nodeName = node.getNodeName(); + + if (nodeName.equals("inst")) { + inst = node.getNodeValue(); + } else if (nodeName.equals("lnType")) { + lnType = node.getNodeValue(); + } else if (nodeName.equals("lnClass")) { + lnClass = node.getNodeValue(); + } else if (nodeName.equals("prefix")) { + prefix = node.getNodeValue(); } - } } - if (ldInst == null) { - throw new SclParseException( - "Required attribute \"ldInst\" not found in FCDA: " + nameAttribute + "!"); + if (inst == null) { + throw new SclParseException("Required attribute \"inst\" not found!"); + } + if (lnType == null) { + throw new SclParseException("Required attribute \"lnType\" not found!"); } - if (lnClass == null) { - throw new SclParseException("Required attribute \"lnClass\" not found in FCDA!"); + throw new SclParseException("Required attribute \"lnClass\" not found!"); } - if (fc == null) { - throw new SclParseException("Required attribute \"fc\" not found in FCDA!"); + + String ref = parentRef + '/' + prefix + lnClass + inst; + + LnType lnTypeDef = typeDefinitions.getLNodeType(lnType); + + List dataObjects = new ArrayList<>(); + + if (lnTypeDef == null) { + throw new SclParseException("LNType " + lnType + " not defined!"); } - if (!doName.isEmpty()) { - - String objectReference = - iedName + ldInst + "/" + prefix + lnClass + lnInst + "." + doName + daName; - - ModelNode fcdaNode = serverModel.findModelNode(objectReference, fc); - - if (fcdaNode == null) { - throw new SclParseException( - "Specified FCDA: " - + objectReference - + " in DataSet: " - + nameAttribute - + " not found in Model."); - } - dsMembers.add((FcModelNode) fcdaNode); - } else { - String objectReference = iedName + ldInst + "/" + prefix + lnClass + lnInst; - ModelNode logicalNode = serverModel.findModelNode(objectReference, null); - if (logicalNode == null) { - throw new SclParseException( - "Specified FCDA: " - + objectReference - + " in DataSet: " - + nameAttribute - + " not found in Model."); - } - List fcDataObjects = ((LogicalNode) logicalNode).getChildren(fc); - for (FcDataObject dataObj : fcDataObjects) { - dsMembers.add(dataObj); - } + for (Do dobject : lnTypeDef.dos) { + + // look for DOI node with the name of the DO + Node doiNodeFound = null; + for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { + Node childNode = lnXmlNode.getChildNodes().item(i); + if ("DOI".equals(childNode.getNodeName())) { + + NamedNodeMap doiAttributes = childNode.getAttributes(); + Node nameAttribute = doiAttributes.getNamedItem("name"); + if (nameAttribute != null && nameAttribute.getNodeValue().equals(dobject.getName())) { + doiNodeFound = childNode; + } + } + } + + dataObjects.addAll( + createFcDataObjects(dobject.getName(), ref, dobject.getType(), doiNodeFound)); } - } - } - DataSet dataSet = new DataSet(lNode.getReference().toString() + '.' + name, dsMembers, false); - return dataSet; - } + // look for ReportControl + for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { + Node childNode = lnXmlNode.getChildNodes().item(i); + if ("ReportControl".equals(childNode.getNodeName())) { + dataObjects.addAll(createReportControlBlocks(childNode, ref)); + } + } - private List createReportControlBlocks(Node xmlNode, String parentRef) - throws SclParseException { + LogicalNode lNode = new LogicalNode(new ObjectReference(ref), dataObjects); - Fc fc = Fc.RP; - NamedNodeMap rcbNodeAttributes = xmlNode.getAttributes(); - Node attribute = rcbNodeAttributes.getNamedItem("buffered"); - if (attribute != null && "true".equalsIgnoreCase(attribute.getNodeValue())) { - fc = Fc.BR; + // look for DataSet definitions + for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { + Node childNode = lnXmlNode.getChildNodes().item(i); + if ("DataSet".equals(childNode.getNodeName())) { + dataSetDefs.add(new LnSubDef(childNode, lNode)); + } + } + return lNode; } - Node nameAttribute = rcbNodeAttributes.getNamedItem("name"); - if (nameAttribute == null) { - throw new SclParseException("Report Control Block has no name attribute."); - } + private DataSet createDataSet(ServerModel serverModel, LogicalNode lNode, Node dsXmlNode) + throws SclParseException { - int maxInstances = 1; - for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++) { - Node childNode = xmlNode.getChildNodes().item(i); - - if ("RptEnabled".equals(childNode.getNodeName())) { - Node rptEnabledMaxAttr = childNode.getAttributes().getNamedItem("max"); - if (rptEnabledMaxAttr != null) { - maxInstances = Integer.parseInt(rptEnabledMaxAttr.getNodeValue()); - if (maxInstances < 1 || maxInstances > 99) { - throw new SclParseException( - "Report Control Block max instances should be between 1 and 99 but is: " - + maxInstances); - } + Node nameAttribute = dsXmlNode.getAttributes().getNamedItem("name"); + if (nameAttribute == null) { + throw new SclParseException("DataSet must have a name"); } - } + + String name = nameAttribute.getNodeValue(); + + List dsMembers = new ArrayList<>(); + + for (int i = 0; i < dsXmlNode.getChildNodes().getLength(); i++) { + Node fcdaXmlNode = dsXmlNode.getChildNodes().item(i); + if ("FCDA".equals(fcdaXmlNode.getNodeName())) { + + // For the definition of FCDA see Table 22 part6 ed2 + + String ldInst = null; + String prefix = ""; + String lnClass = null; + String lnInst = ""; + String doName = ""; + String daName = ""; + Fc fc = null; + + NamedNodeMap attributes = fcdaXmlNode.getAttributes(); + + for (int j = 0; j < attributes.getLength(); j++) { + Node node = attributes.item(j); + String nodeName = node.getNodeName(); + + switch (nodeName) { + case "ldInst": + ldInst = node.getNodeValue(); + break; + case "lnInst": + lnInst = node.getNodeValue(); + break; + case "lnClass": + lnClass = node.getNodeValue(); + break; + case "prefix": + prefix = node.getNodeValue(); + break; + case "doName": + doName = node.getNodeValue(); + break; + case "daName": + if (!node.getNodeValue().isEmpty()) { + daName = "." + node.getNodeValue(); + } + break; + case "fc": + fc = Fc.fromString(node.getNodeValue()); + if (fc == null) { + throw new SclParseException("FCDA contains invalid FC: " + node.getNodeValue()); + } + break; + } + } + + if (ldInst == null) { + throw new SclParseException( + "Required attribute \"ldInst\" not found in FCDA: " + nameAttribute + "!"); + } + + if (lnClass == null) { + throw new SclParseException("Required attribute \"lnClass\" not found in FCDA!"); + } + if (fc == null) { + throw new SclParseException("Required attribute \"fc\" not found in FCDA!"); + } + if (!doName.isEmpty()) { + + String objectReference = + iedName + ldInst + "/" + prefix + lnClass + lnInst + "." + doName + daName; + + ModelNode fcdaNode = serverModel.findModelNode(objectReference, fc); + + if (fcdaNode == null) { + throw new SclParseException( + "Specified FCDA: " + + objectReference + + " in DataSet: " + + nameAttribute + + " not found in Model."); + } + dsMembers.add((FcModelNode) fcdaNode); + } else { + String objectReference = iedName + ldInst + "/" + prefix + lnClass + lnInst; + ModelNode logicalNode = serverModel.findModelNode(objectReference, null); + if (logicalNode == null) { + throw new SclParseException( + "Specified FCDA: " + + objectReference + + " in DataSet: " + + nameAttribute + + " not found in Model."); + } + List fcDataObjects = ((LogicalNode) logicalNode).getChildren(fc); + for (FcDataObject dataObj : fcDataObjects) { + dsMembers.add(dataObj); + } + } + } + } + + DataSet dataSet = new DataSet(lNode.getReference().toString() + '.' + name, dsMembers, false); + return dataSet; } - List rcbInstances = new ArrayList<>(maxInstances); + private List createReportControlBlocks(Node xmlNode, String parentRef) + throws SclParseException { + + Fc fc = Fc.RP; + NamedNodeMap rcbNodeAttributes = xmlNode.getAttributes(); + Node attribute = rcbNodeAttributes.getNamedItem("buffered"); + if (attribute != null && "true".equalsIgnoreCase(attribute.getNodeValue())) { + fc = Fc.BR; + } + + Node nameAttribute = rcbNodeAttributes.getNamedItem("name"); + if (nameAttribute == null) { + throw new SclParseException("Report Control Block has no name attribute."); + } + + int maxInstances = 1; + for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++) { + Node childNode = xmlNode.getChildNodes().item(i); + + if ("RptEnabled".equals(childNode.getNodeName())) { + Node rptEnabledMaxAttr = childNode.getAttributes().getNamedItem("max"); + if (rptEnabledMaxAttr != null) { + maxInstances = Integer.parseInt(rptEnabledMaxAttr.getNodeValue()); + if (maxInstances < 1 || maxInstances > 99) { + throw new SclParseException( + "Report Control Block max instances should be between 1 and 99 but is: " + + maxInstances); + } + } + } + } + + List rcbInstances = new ArrayList<>(maxInstances); - for (int z = 1; z <= maxInstances; z++) { + for (int z = 1; z <= maxInstances; z++) { - ObjectReference reportObjRef; + ObjectReference reportObjRef; - if (maxInstances == 1) { + if (maxInstances == 1) { - reportObjRef = new ObjectReference(parentRef + "." + nameAttribute.getNodeValue()); - } else { - reportObjRef = - new ObjectReference( - parentRef + "." + nameAttribute.getNodeValue() + String.format("%02d", z)); - } + reportObjRef = new ObjectReference(parentRef + "." + nameAttribute.getNodeValue()); + } else { + reportObjRef = + new ObjectReference( + parentRef + "." + nameAttribute.getNodeValue() + String.format("%02d", z)); + } - BdaTriggerConditions trigOps = - new BdaTriggerConditions(new ObjectReference(reportObjRef + ".TrgOps"), fc); - BdaOptFlds optFields = new BdaOptFlds(new ObjectReference(reportObjRef + ".OptFlds"), fc); - for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++) { - Node childNode = xmlNode.getChildNodes().item(i); - if (childNode.getNodeName().equals("TrgOps")) { + BdaTriggerConditions trigOps = + new BdaTriggerConditions(new ObjectReference(reportObjRef + ".TrgOps"), fc); + BdaOptFlds optFields = new BdaOptFlds(new ObjectReference(reportObjRef + ".OptFlds"), fc); + for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++) { + Node childNode = xmlNode.getChildNodes().item(i); + if (childNode.getNodeName().equals("TrgOps")) { + + NamedNodeMap attributes = childNode.getAttributes(); + + if (attributes != null) { + for (int j = 0; j < attributes.getLength(); j++) { + Node node = attributes.item(j); + String nodeName = node.getNodeName(); + + if ("dchg".equals(nodeName)) { + trigOps.setDataChange(node.getNodeValue().equalsIgnoreCase("true")); + } else if ("qchg".equals(nodeName)) { + trigOps.setQualityChange(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("dupd".equals(nodeName)) { + trigOps.setDataUpdate(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("period".equals(nodeName)) { + trigOps.setIntegrity(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("gi".equals(nodeName)) { + trigOps.setGeneralInterrogation(node.getNodeValue().equalsIgnoreCase("true")); + } + } + } + } else if ("OptFields".equals(childNode.getNodeName())) { + + NamedNodeMap attributes = childNode.getAttributes(); + + if (attributes != null) { + for (int j = 0; j < attributes.getLength(); j++) { + + Node node = attributes.item(j); + String nodeName = node.getNodeName(); + + if ("seqNum".equals(nodeName)) { + optFields.setSequenceNumber(node.getNodeValue().equalsIgnoreCase("true")); + } else if ("timeStamp".equals(nodeName)) { + optFields.setReportTimestamp(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("reasonCode".equals(nodeName)) { + optFields.setReasonForInclusion(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("dataSet".equals(nodeName)) { + optFields.setDataSetName(node.getNodeValue().equalsIgnoreCase("true")); + + } + // not supported for now + // else if (nodeName.equals("dataRef")) { + // optFields.setDataReference(node.getNodeValue().equals("true")); + // + // } + else if (nodeName.equals("bufOvfl")) { + optFields.setBufferOverflow(node.getNodeValue().equalsIgnoreCase("true")); + + } else if (nodeName.equals("entryID")) { + optFields.setEntryId(node.getNodeValue().equalsIgnoreCase("true")); + } + // not supported for now: + // else if (nodeName.equals("configRef")) { + // optFields.setConfigRevision(node.getNodeValue().equals("true")); + // } + } + } + } else if ("RptEnabled".equals(childNode.getNodeName())) { + Node rptEnabledMaxAttr = childNode.getAttributes().getNamedItem("max"); + if (rptEnabledMaxAttr != null) { + maxInstances = Integer.parseInt(rptEnabledMaxAttr.getNodeValue()); + if (maxInstances < 1 || maxInstances > 99) { + throw new SclParseException( + "Report Control Block max instances should be between 1 and 99 but is: " + + maxInstances); + } + } + } + } - NamedNodeMap attributes = childNode.getAttributes(); + if (fc == Fc.RP) { + optFields.setEntryId(false); + optFields.setBufferOverflow(false); + } - if (attributes != null) { - for (int j = 0; j < attributes.getLength(); j++) { - Node node = attributes.item(j); - String nodeName = node.getNodeName(); + List children = new ArrayList<>(); - if ("dchg".equals(nodeName)) { - trigOps.setDataChange(node.getNodeValue().equalsIgnoreCase("true")); - } else if ("qchg".equals(nodeName)) { - trigOps.setQualityChange(node.getNodeValue().equalsIgnoreCase("true")); + BdaVisibleString rptId = + new BdaVisibleString( + new ObjectReference(reportObjRef + ".RptID"), fc, "", 129, false, false); + attribute = rcbNodeAttributes.getNamedItem("rptID"); + if (attribute != null) { + rptId.setValue(attribute.getNodeValue().getBytes(UTF_8)); + } else { + rptId.setValue(reportObjRef.toString()); + } - } else if ("dupd".equals(nodeName)) { - trigOps.setDataUpdate(node.getNodeValue().equalsIgnoreCase("true")); + children.add(rptId); - } else if ("period".equals(nodeName)) { - trigOps.setIntegrity(node.getNodeValue().equalsIgnoreCase("true")); + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef + ".RptEna"), fc, "", false, false)); - } else if ("gi".equals(nodeName)) { - trigOps.setGeneralInterrogation(node.getNodeValue().equalsIgnoreCase("true")); - } + if (fc == Fc.RP) { + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef + ".Resv"), fc, "", false, false)); } - } - } else if ("OptFields".equals(childNode.getNodeName())) { - - NamedNodeMap attributes = childNode.getAttributes(); - - if (attributes != null) { - for (int j = 0; j < attributes.getLength(); j++) { - - Node node = attributes.item(j); - String nodeName = node.getNodeName(); - - if ("seqNum".equals(nodeName)) { - optFields.setSequenceNumber(node.getNodeValue().equalsIgnoreCase("true")); - } else if ("timeStamp".equals(nodeName)) { - optFields.setReportTimestamp(node.getNodeValue().equalsIgnoreCase("true")); - - } else if ("reasonCode".equals(nodeName)) { - optFields.setReasonForInclusion(node.getNodeValue().equalsIgnoreCase("true")); - - } else if ("dataSet".equals(nodeName)) { - optFields.setDataSetName(node.getNodeValue().equalsIgnoreCase("true")); - - } - // not supported for now - // else if (nodeName.equals("dataRef")) { - // optFields.setDataReference(node.getNodeValue().equals("true")); - // - // } - else if (nodeName.equals("bufOvfl")) { - optFields.setBufferOverflow(node.getNodeValue().equalsIgnoreCase("true")); - - } else if (nodeName.equals("entryID")) { - optFields.setEntryId(node.getNodeValue().equalsIgnoreCase("true")); - } - // not supported for now: - // else if (nodeName.equals("configRef")) { - // optFields.setConfigRevision(node.getNodeValue().equals("true")); - // } + + BdaVisibleString datSet = + new BdaVisibleString( + new ObjectReference(reportObjRef + ".DatSet"), fc, "", 129, false, false); + + attribute = xmlNode.getAttributes().getNamedItem("datSet"); + if (attribute != null) { + String nodeValue = attribute.getNodeValue(); + String dataSetName = parentRef + "$" + nodeValue; + datSet.setValue(dataSetName.getBytes(UTF_8)); } - } - } else if ("RptEnabled".equals(childNode.getNodeName())) { - Node rptEnabledMaxAttr = childNode.getAttributes().getNamedItem("max"); - if (rptEnabledMaxAttr != null) { - maxInstances = Integer.parseInt(rptEnabledMaxAttr.getNodeValue()); - if (maxInstances < 1 || maxInstances > 99) { - throw new SclParseException( - "Report Control Block max instances should be between 1 and 99 but is: " - + maxInstances); + children.add(datSet); + + BdaInt32U confRef = + new BdaInt32U( + new ObjectReference(reportObjRef + ".ConfRev"), fc, "", false, false); + attribute = xmlNode.getAttributes().getNamedItem("confRev"); + if (attribute == null) { + throw new SclParseException( + "Report Control Block does not contain mandatory attribute confRev"); } - } - } - } - - if (fc == Fc.RP) { - optFields.setEntryId(false); - optFields.setBufferOverflow(false); - } - - List children = new ArrayList<>(); - - BdaVisibleString rptId = - new BdaVisibleString( - new ObjectReference(reportObjRef.toString() + ".RptID"), fc, "", 129, false, false); - attribute = rcbNodeAttributes.getNamedItem("rptID"); - if (attribute != null) { - rptId.setValue(attribute.getNodeValue().getBytes(UTF_8)); - } else { - rptId.setValue(reportObjRef.toString()); - } - - children.add(rptId); - - children.add( - new BdaBoolean( - new ObjectReference(reportObjRef.toString() + ".RptEna"), fc, "", false, false)); - - if (fc == Fc.RP) { - children.add( - new BdaBoolean( - new ObjectReference(reportObjRef.toString() + ".Resv"), fc, "", false, false)); - } - - BdaVisibleString datSet = - new BdaVisibleString( - new ObjectReference(reportObjRef.toString() + ".DatSet"), fc, "", 129, false, false); - - attribute = xmlNode.getAttributes().getNamedItem("datSet"); - if (attribute != null) { - String nodeValue = attribute.getNodeValue(); - String dataSetName = parentRef + "$" + nodeValue; - datSet.setValue(dataSetName.getBytes(UTF_8)); - } - children.add(datSet); - - BdaInt32U confRef = - new BdaInt32U( - new ObjectReference(reportObjRef.toString() + ".ConfRev"), fc, "", false, false); - attribute = xmlNode.getAttributes().getNamedItem("confRev"); - if (attribute == null) { - throw new SclParseException( - "Report Control Block does not contain mandatory attribute confRev"); - } - confRef.setValue(Long.parseLong(attribute.getNodeValue())); - children.add(confRef); - - children.add(optFields); - - BdaInt32U bufTm = - new BdaInt32U( - new ObjectReference(reportObjRef.toString() + ".BufTm"), fc, "", false, false); - attribute = xmlNode.getAttributes().getNamedItem("bufTime"); - if (attribute != null) { - bufTm.setValue(Long.parseLong(attribute.getNodeValue())); - } - children.add(bufTm); - - children.add( - new BdaInt8U( - new ObjectReference(reportObjRef.toString() + ".SqNum"), fc, "", false, false)); - - children.add(trigOps); - - BdaInt32U intgPd = - new BdaInt32U( - new ObjectReference(reportObjRef.toString() + ".IntgPd"), fc, "", false, false); - attribute = xmlNode.getAttributes().getNamedItem("intgPd"); - if (attribute != null) { - intgPd.setValue(Long.parseLong(attribute.getNodeValue())); - } - children.add(intgPd); - - children.add( - new BdaBoolean( - new ObjectReference(reportObjRef.toString() + ".GI"), fc, "", false, false)); - - Rcb rcb = null; - - if (fc == Fc.BR) { - - children.add( - new BdaBoolean( - new ObjectReference(reportObjRef.toString() + ".PurgeBuf"), fc, "", false, false)); - - children.add( - new BdaOctetString( - new ObjectReference(reportObjRef.toString() + ".EntryID"), - fc, - "", - 8, - false, - false)); - - children.add( - new BdaEntryTime( - new ObjectReference(reportObjRef.toString() + ".TimeOfEntry"), - fc, - "", - false, - false)); - - if (useResvTmsAttributes) { - children.add( - new BdaInt16( - new ObjectReference(reportObjRef.toString() + ".ResvTms"), fc, "", false, false)); - } + confRef.setValue(Long.parseLong(attribute.getNodeValue())); + children.add(confRef); + + children.add(optFields); - children.add( - new BdaOctetString( - new ObjectReference(reportObjRef.toString() + ".Owner"), fc, "", 64, false, false)); + BdaInt32U bufTm = + new BdaInt32U( + new ObjectReference(reportObjRef + ".BufTm"), fc, "", false, false); + attribute = xmlNode.getAttributes().getNamedItem("bufTime"); + if (attribute != null) { + bufTm.setValue(Long.parseLong(attribute.getNodeValue())); + } + children.add(bufTm); - rcb = new Brcb(reportObjRef, children); + children.add( + new BdaInt8U( + new ObjectReference(reportObjRef + ".SqNum"), fc, "", false, false)); - } else { - children.add( - new BdaOctetString( - new ObjectReference(reportObjRef.toString() + ".Owner"), fc, "", 64, false, false)); + children.add(trigOps); - rcb = new Urcb(reportObjRef, children); - } + BdaInt32U intgPd = + new BdaInt32U( + new ObjectReference(reportObjRef + ".IntgPd"), fc, "", false, false); + attribute = xmlNode.getAttributes().getNamedItem("intgPd"); + if (attribute != null) { + intgPd.setValue(Long.parseLong(attribute.getNodeValue())); + } + children.add(intgPd); + + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef + ".GI"), fc, "", false, false)); + + Rcb rcb; + + if (fc == Fc.BR) { + + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef + ".PurgeBuf"), fc, "", false, false)); + + children.add( + new BdaOctetString( + new ObjectReference(reportObjRef + ".EntryID"), + fc, + "", + 8, + false, + false)); + + children.add( + new BdaEntryTime( + new ObjectReference(reportObjRef + ".TimeOfEntry"), + fc, + "", + false, + false)); + + if (useResvTmsAttributes) { + children.add( + new BdaInt16( + new ObjectReference(reportObjRef + ".ResvTms"), fc, "", false, false)); + } + + children.add( + new BdaOctetString( + new ObjectReference(reportObjRef + ".Owner"), fc, "", 64, false, false)); + + rcb = new Brcb(reportObjRef, children); + + } else { + children.add( + new BdaOctetString( + new ObjectReference(reportObjRef + ".Owner"), fc, "", 64, false, false)); + + rcb = new Urcb(reportObjRef, children); + } - rcbInstances.add(rcb); + rcbInstances.add(rcb); + } + + return rcbInstances; } - return rcbInstances; - } + private List createFcDataObjects( + String name, String parentRef, String doTypeID, Node doiNode) throws SclParseException { - private List createFcDataObjects( - String name, String parentRef, String doTypeID, Node doiNode) throws SclParseException { + DoType doType = typeDefinitions.getDOType(doTypeID); - DoType doType = typeDefinitions.getDOType(doTypeID); + if (doType == null) { + throw new SclParseException("DO type " + doTypeID + " not defined!"); + } - if (doType == null) { - throw new SclParseException("DO type " + doTypeID + " not defined!"); - } + String ref = parentRef + '.' + name; - String ref = parentRef + '.' + name; + List childNodes = new ArrayList<>(); - List childNodes = new ArrayList<>(); + for (Da dattr : doType.das) { - for (Da dattr : doType.das) { + // look for DAI node with the name of the DA + Node iNodeFound = findINode(doiNode, dattr.getName()); - // look for DAI node with the name of the DA - Node iNodeFound = findINode(doiNode, dattr.getName()); + if (dattr.getCount() >= 1) { + childNodes.add(createArrayOfDataAttributes(ref + '.' + dattr.getName(), dattr, iNodeFound)); + } else { + childNodes.add( + createDataAttribute( + ref + '.' + dattr.getName(), + dattr.getFc(), + dattr, + iNodeFound, + false, + false, + false)); + } + } - if (dattr.getCount() >= 1) { - childNodes.add(createArrayOfDataAttributes(ref + '.' + dattr.getName(), dattr, iNodeFound)); - } else { - childNodes.add( - createDataAttribute( - ref + '.' + dattr.getName(), - dattr.getFc(), - dattr, - iNodeFound, - false, - false, - false)); - } - } + for (Sdo sdo : doType.sdos) { - for (Sdo sdo : doType.sdos) { + // parsing Arrays of SubDataObjects is ignored for now because no SCL file was found to test + // against. The + // only DO that contains an Array of SDOs is Harmonic Value (HMV). The Kalkitech SCL Manager + // handles the + // array of SDOs in HMV as an array of DAs. - // parsing Arrays of SubDataObjects is ignored for now because no SCL file was found to test - // against. The - // only DO that contains an Array of SDOs is Harmonic Value (HMV). The Kalkitech SCL Manager - // handles the - // array of SDOs in HMV as an array of DAs. + Node iNodeFound = findINode(doiNode, sdo.getName()); - Node iNodeFound = findINode(doiNode, sdo.getName()); + childNodes.addAll(createFcDataObjects(sdo.getName(), ref, sdo.getType(), iNodeFound)); + } - childNodes.addAll(createFcDataObjects(sdo.getName(), ref, sdo.getType(), iNodeFound)); - } + Map> subFCDataMap = new LinkedHashMap<>(); - Map> subFCDataMap = new LinkedHashMap<>(); + for (Fc fc : Fc.values()) { + subFCDataMap.put(fc, new ArrayList<>()); + } - for (Fc fc : Fc.values()) { - subFCDataMap.put(fc, new ArrayList<>()); - } + for (ModelNode childNode : childNodes) { + subFCDataMap.get(((FcModelNode) childNode).getFc()).add((FcModelNode) childNode); + } - for (ModelNode childNode : childNodes) { - subFCDataMap.get(((FcModelNode) childNode).getFc()).add((FcModelNode) childNode); - } + List fcDataObjects = new ArrayList<>(); + ObjectReference objectReference = new ObjectReference(ref); - List fcDataObjects = new ArrayList<>(); - ObjectReference objectReference = new ObjectReference(ref); + for (Fc fc : Fc.values()) { + if (subFCDataMap.get(fc).size() > 0) { + fcDataObjects.add(new FcDataObject(objectReference, fc, subFCDataMap.get(fc))); + } + } - for (Fc fc : Fc.values()) { - if (subFCDataMap.get(fc).size() > 0) { - fcDataObjects.add(new FcDataObject(objectReference, fc, subFCDataMap.get(fc))); - } + return fcDataObjects; } - return fcDataObjects; - } + private Node findINode(Node iNode, String dattrName) { - private Node findINode(Node iNode, String dattrName) { + if (iNode == null) { + return null; + } - if (iNode == null) { - return null; + for (int i = 0; i < iNode.getChildNodes().getLength(); i++) { + Node childNode = iNode.getChildNodes().item(i); + if (childNode.getAttributes() != null) { + Node nameAttribute = childNode.getAttributes().getNamedItem("name"); + if (nameAttribute != null && nameAttribute.getNodeValue().equals(dattrName)) { + return childNode; + } + } + } + return null; } - for (int i = 0; i < iNode.getChildNodes().getLength(); i++) { - Node childNode = iNode.getChildNodes().item(i); - if (childNode.getAttributes() != null) { - Node nameAttribute = childNode.getAttributes().getNamedItem("name"); - if (nameAttribute != null && nameAttribute.getNodeValue().equals(dattrName)) { - return childNode; + private Array createArrayOfDataAttributes(String ref, Da dataAttribute, Node iXmlNode) + throws SclParseException { + + Fc fc = dataAttribute.getFc(); + int size = dataAttribute.getCount(); + + List arrayItems = new ArrayList<>(); + for (int i = 0; i < size; i++) { + // TODO go down the iXmlNode using the ix attribute? + arrayItems.add( + createDataAttribute( + ref + '(' + i + ')', + fc, + dataAttribute, + iXmlNode, + dataAttribute.isDchg(), + dataAttribute.isDupd(), + dataAttribute.isQchg())); } - } - } - return null; - } - - private Array createArrayOfDataAttributes(String ref, Da dataAttribute, Node iXmlNode) - throws SclParseException { - - Fc fc = dataAttribute.getFc(); - int size = dataAttribute.getCount(); - - List arrayItems = new ArrayList<>(); - for (int i = 0; i < size; i++) { - // TODO go down the iXmlNode using the ix attribute? - arrayItems.add( - createDataAttribute( - ref + '(' + i + ')', - fc, - dataAttribute, - iXmlNode, - dataAttribute.isDchg(), - dataAttribute.isDupd(), - dataAttribute.isQchg())); - } - return new Array(new ObjectReference(ref), fc, arrayItems); - } - - /** returns a ConstructedDataAttribute or BasicDataAttribute */ - private FcModelNode createDataAttribute( - String ref, - Fc fc, - AbstractDataAttribute dattr, - Node iXmlNode, - boolean dchg, - boolean dupd, - boolean qchg) - throws SclParseException { - - if (dattr instanceof Da) { - Da dataAttribute = (Da) dattr; - dchg = dataAttribute.isDchg(); - dupd = dataAttribute.isDupd(); - qchg = dataAttribute.isQchg(); + return new Array(new ObjectReference(ref), fc, arrayItems); } - String bType = dattr.getbType(); + /** + * returns a ConstructedDataAttribute or BasicDataAttribute + */ + private FcModelNode createDataAttribute( + String ref, + Fc fc, + AbstractDataAttribute dattr, + Node iXmlNode, + boolean dchg, + boolean dupd, + boolean qchg) + throws SclParseException { + + if (dattr instanceof Da) { + Da dataAttribute = (Da) dattr; + dchg = dataAttribute.isDchg(); + dupd = dataAttribute.isDupd(); + qchg = dataAttribute.isQchg(); + } - if (bType.equals("Struct")) { - DaType datype = typeDefinitions.getDaType(dattr.getType()); + String bType = dattr.getbType(); - if (datype == null) { - throw new SclParseException("DAType " + dattr.getbType() + " not declared!"); - } + if (bType.equals("Struct")) { + DaType datype = typeDefinitions.getDaType(dattr.getType()); - List subDataAttributes = new ArrayList<>(); - for (Bda bda : datype.bdas) { + if (datype == null) { + throw new SclParseException("DAType " + dattr.getbType() + " not declared!"); + } - Node iNodeFound = findINode(iXmlNode, bda.getName()); + List subDataAttributes = new ArrayList<>(); + for (Bda bda : datype.bdas) { - subDataAttributes.add( - createDataAttribute(ref + '.' + bda.getName(), fc, bda, iNodeFound, dchg, dupd, qchg)); - } - return new ConstructedDataAttribute(new ObjectReference(ref), fc, subDataAttributes); - } + Node iNodeFound = findINode(iXmlNode, bda.getName()); - String val = null; - String sAddr = null; - if (iXmlNode != null) { - NamedNodeMap attributeMap = iXmlNode.getAttributes(); - Node sAddrAttribute = attributeMap.getNamedItem("sAddr"); - if (sAddrAttribute != null) { - sAddr = sAddrAttribute.getNodeValue(); - } - - NodeList elements = iXmlNode.getChildNodes(); - for (int i = 0; i < elements.getLength(); i++) { - Node node = elements.item(i); - if (node.getNodeName().equals("Val")) { - val = node.getTextContent(); + subDataAttributes.add( + createDataAttribute(ref + '.' + bda.getName(), fc, bda, iNodeFound, dchg, dupd, qchg)); + } + return new ConstructedDataAttribute(new ObjectReference(ref), fc, subDataAttributes); } - } - if (val == null) { - // insert value from DA element - val = dattr.value; - } - } - if (bType.equals("BOOLEAN")) { - BdaBoolean bda = new BdaBoolean(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - if (val.equalsIgnoreCase("true") || val.equals("1")) { - bda.setValue(true); - } else if (val.equalsIgnoreCase("false") || val.equals("0")) { - bda.setValue(false); - } else { - throw new SclParseException("invalid boolean configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT8")) { - BdaInt8 bda = new BdaInt8(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Byte.parseByte(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT8 configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT16")) { - BdaInt16 bda = new BdaInt16(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Short.parseShort(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT16 configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT32")) { - BdaInt32 bda = new BdaInt32(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Integer.parseInt(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT32 configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT64")) { - BdaInt64 bda = new BdaInt64(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Long.parseLong(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT64 configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT128")) { - BdaInt128 bda = new BdaInt128(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Long.parseLong(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT128 configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT8U")) { - BdaInt8U bda = new BdaInt8U(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Short.parseShort(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT8U configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT16U")) { - BdaInt16U bda = new BdaInt16U(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Integer.parseInt(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT16U configured value: " + val); - } - } - return bda; - } else if (bType.equals("INT32U")) { - BdaInt32U bda = new BdaInt32U(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setValue(Long.parseLong(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid INT32U configured value: " + val); - } - } - return bda; - } else if (bType.equals("FLOAT32")) { - BdaFloat32 bda = new BdaFloat32(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setFloat(Float.parseFloat(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid FLOAT32 configured value: " + val); - } - } - return bda; - } else if (bType.equals("FLOAT64")) { - BdaFloat64 bda = new BdaFloat64(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - try { - bda.setDouble(Double.parseDouble(val)); - } catch (NumberFormatException e) { - throw new SclParseException("invalid FLOAT64 configured value: " + val); - } - } - return bda; - } else if (bType.startsWith("VisString")) { - BdaVisibleString bda = - new BdaVisibleString( - new ObjectReference(ref), - fc, - sAddr, - Integer.parseInt(dattr.getbType().substring(9)), - dchg, - dupd); - if (val != null) { - bda.setValue(val.getBytes(UTF_8)); - } - return bda; - } else if (bType.startsWith("Unicode")) { - BdaUnicodeString bda = - new BdaUnicodeString( - new ObjectReference(ref), - fc, - sAddr, - Integer.parseInt(dattr.getbType().substring(7)), - dchg, - dupd); - if (val != null) { - bda.setValue(val.getBytes(UTF_8)); - } - return bda; - } else if (bType.startsWith("Octet")) { - BdaOctetString bda = - new BdaOctetString( - new ObjectReference(ref), - fc, - sAddr, - Integer.parseInt(dattr.getbType().substring(5)), - dchg, - dupd); - if (val != null) { - // TODO - // throw new SclParseException("parsing configured value for octet string is not supported - // yet."); - } - return bda; - } else if (bType.equals("Quality")) { - return new BdaQuality(new ObjectReference(ref), fc, sAddr, qchg); - } else if (bType.equals("Check")) { - return new BdaCheck(new ObjectReference(ref)); - } else if (bType.equals("Dbpos")) { - return new BdaDoubleBitPos(new ObjectReference(ref), fc, sAddr, dchg, dupd); - } else if (bType.equals("Tcmd")) { - return new BdaTapCommand(new ObjectReference(ref), fc, sAddr, dchg, dupd); - } else if (bType.equals("OptFlds")) { - return new BdaOptFlds(new ObjectReference(ref), fc); - } else if (bType.equals("TrgOps")) { - return new BdaTriggerConditions(new ObjectReference(ref), fc); - } else if (bType.equals("EntryID")) { - return new BdaOctetString(new ObjectReference(ref), fc, sAddr, 8, dchg, dupd); - } else if (bType.equals("EntryTime")) { - return new BdaEntryTime(new ObjectReference(ref), fc, sAddr, dchg, dupd); - } else if (bType.equals("PhyComAddr")) { - // TODO not correct! - return new BdaOctetString(new ObjectReference(ref), fc, sAddr, 6, dchg, dupd); - } else if (bType.equals("Timestamp")) { - BdaTimestamp bda = new BdaTimestamp(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - // TODO - throw new SclParseException("parsing configured value for TIMESTAMP is not supported yet."); - } - return bda; - } else if (bType.equals("Enum")) { - String type = dattr.getType(); - if (type == null) { - throw new SclParseException("The exact type of the enumeration is not set."); - } - EnumType enumType = typeDefinitions.getEnumType(type); - - if (enumType == null) { - throw new SclParseException("Definition of enum type: " + type + " not found."); - } - - if (enumType.max > 127 || enumType.min < -128) { - BdaInt16 bda = new BdaInt16(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - for (EnumVal enumVal : enumType.getValues()) { - if (val.equals(enumVal.getId())) { - bda.setValue((short) enumVal.getOrd()); - return bda; + String val = null; + String sAddr = null; + if (iXmlNode != null) { + NamedNodeMap attributeMap = iXmlNode.getAttributes(); + Node sAddrAttribute = attributeMap.getNamedItem("sAddr"); + if (sAddrAttribute != null) { + sAddr = sAddrAttribute.getNodeValue(); + } + + NodeList elements = iXmlNode.getChildNodes(); + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (node.getNodeName().equals("Val")) { + val = node.getTextContent(); + } + } + if (val == null) { + // insert value from DA element + val = dattr.value; } - } - throw new SclParseException("unknown enum value: " + val); } - return bda; - } else { - BdaInt8 bda = new BdaInt8(new ObjectReference(ref), fc, sAddr, dchg, dupd); - if (val != null) { - for (EnumVal enumVal : enumType.getValues()) { - if (val.equals(enumVal.getId())) { - bda.setValue((byte) enumVal.getOrd()); - return bda; + + if (bType.equals("BOOLEAN")) { + BdaBoolean bda = new BdaBoolean(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + if (val.equalsIgnoreCase("true") || val.equals("1")) { + bda.setValue(true); + } else if (val.equalsIgnoreCase("false") || val.equals("0")) { + bda.setValue(false); + } else { + throw new SclParseException("invalid boolean configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT8")) { + BdaInt8 bda = new BdaInt8(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Byte.parseByte(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT8 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT16")) { + BdaInt16 bda = new BdaInt16(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Short.parseShort(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT16 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT32")) { + BdaInt32 bda = new BdaInt32(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Integer.parseInt(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT32 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT64")) { + BdaInt64 bda = new BdaInt64(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Long.parseLong(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT64 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT128")) { + BdaInt128 bda = new BdaInt128(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Long.parseLong(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT128 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT8U")) { + BdaInt8U bda = new BdaInt8U(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Short.parseShort(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT8U configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT16U")) { + BdaInt16U bda = new BdaInt16U(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Integer.parseInt(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT16U configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT32U")) { + BdaInt32U bda = new BdaInt32U(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Long.parseLong(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT32U configured value: " + val); + } + } + return bda; + } else if (bType.equals("FLOAT32")) { + BdaFloat32 bda = new BdaFloat32(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setFloat(Float.parseFloat(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid FLOAT32 configured value: " + val); + } + } + return bda; + } else if (bType.equals("FLOAT64")) { + BdaFloat64 bda = new BdaFloat64(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setDouble(Double.parseDouble(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid FLOAT64 configured value: " + val); + } } - } - throw new SclParseException("unknown enum value: " + val); + return bda; + } else if (bType.startsWith("VisString")) { + BdaVisibleString bda = + new BdaVisibleString( + new ObjectReference(ref), + fc, + sAddr, + Integer.parseInt(dattr.getbType().substring(9)), + dchg, + dupd); + if (val != null) { + bda.setValue(val.getBytes(UTF_8)); + } + return bda; + } else if (bType.startsWith("Unicode")) { + BdaUnicodeString bda = + new BdaUnicodeString( + new ObjectReference(ref), + fc, + sAddr, + Integer.parseInt(dattr.getbType().substring(7)), + dchg, + dupd); + if (val != null) { + bda.setValue(val.getBytes(UTF_8)); + } + return bda; + } else if (bType.startsWith("Octet")) { + BdaOctetString bda = + new BdaOctetString( + new ObjectReference(ref), + fc, + sAddr, + Integer.parseInt(dattr.getbType().substring(5)), + dchg, + dupd); + if (val != null) { + // TODO + // throw new SclParseException("parsing configured value for octet string is not supported + // yet."); + } + return bda; + } else if (bType.equals("Quality")) { + return new BdaQuality(new ObjectReference(ref), fc, sAddr, qchg); + } else if (bType.equals("Check")) { + return new BdaCheck(new ObjectReference(ref)); + } else if (bType.equals("Dbpos")) { + return new BdaDoubleBitPos(new ObjectReference(ref), fc, sAddr, dchg, dupd); + } else if (bType.equals("Tcmd")) { + return new BdaTapCommand(new ObjectReference(ref), fc, sAddr, dchg, dupd); + } else if (bType.equals("OptFlds")) { + return new BdaOptFlds(new ObjectReference(ref), fc); + } else if (bType.equals("TrgOps")) { + return new BdaTriggerConditions(new ObjectReference(ref), fc); + } else if (bType.equals("EntryID")) { + return new BdaOctetString(new ObjectReference(ref), fc, sAddr, 8, dchg, dupd); + } else if (bType.equals("EntryTime")) { + return new BdaEntryTime(new ObjectReference(ref), fc, sAddr, dchg, dupd); + } else if (bType.equals("PhyComAddr")) { + // TODO not correct! + return new BdaOctetString(new ObjectReference(ref), fc, sAddr, 6, dchg, dupd); + } else if (bType.equals("Timestamp")) { + BdaTimestamp bda = new BdaTimestamp(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + // TODO + throw new SclParseException("parsing configured value for TIMESTAMP is not supported yet."); + } + return bda; + } else if (bType.equals("Enum")) { + String type = dattr.getType(); + if (type == null) { + throw new SclParseException("The exact type of the enumeration is not set."); + } + EnumType enumType = typeDefinitions.getEnumType(type); + + if (enumType == null) { + throw new SclParseException("Definition of enum type: " + type + " not found."); + } + + if (enumType.max > 127 || enumType.min < -128) { + BdaInt16 bda = new BdaInt16(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + for (EnumVal enumVal : enumType.getValues()) { + if (val.equals(enumVal.getId())) { + bda.setValue((short) enumVal.getOrd()); + return bda; + } + } + throw new SclParseException("unknown enum value: " + val); + } + return bda; + } else { + BdaInt8 bda = new BdaInt8(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + for (EnumVal enumVal : enumType.getValues()) { + if (val.equals(enumVal.getId())) { + bda.setValue((byte) enumVal.getOrd()); + return bda; + } + } + throw new SclParseException("unknown enum value: " + val); + } + return bda; + } + } else if (bType.equals("ObjRef")) { + BdaVisibleString bda = + new BdaVisibleString(new ObjectReference(ref), fc, sAddr, 129, dchg, dupd); + if (val != null) { + bda.setValue(val.getBytes(UTF_8)); + } + return bda; + } else { + throw new SclParseException("Invalid bType: " + bType); } - return bda; - } - } else if (bType.equals("ObjRef")) { - BdaVisibleString bda = - new BdaVisibleString(new ObjectReference(ref), fc, sAddr, 129, dchg, dupd); - if (val != null) { - bda.setValue(val.getBytes(UTF_8)); - } - return bda; - } else { - throw new SclParseException("Invalid bType: " + bType); } - } -} +} \ No newline at end of file diff --git a/src/main/java/com/beanit/iec61850bean/ServerModel.java b/src/main/java/com/beanit/iec61850bean/ServerModel.java index 9a4f59f..0330770 100644 --- a/src/main/java/com/beanit/iec61850bean/ServerModel.java +++ b/src/main/java/com/beanit/iec61850bean/ServerModel.java @@ -17,384 +17,389 @@ import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific; import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; + +import java.util.*; public final class ServerModel extends ModelNode { - private final Map dataSets = new LinkedHashMap<>(); + private final Map dataSets = new LinkedHashMap<>(); - private final Map urcbs = new HashMap<>(); - private final Map brcbs = new HashMap<>(); + private final Map urcbs = new HashMap<>(); + private final Map brcbs = new HashMap<>(); - public ServerModel(List logicalDevices, Collection dataSets) { - children = new LinkedHashMap<>(); - objectReference = null; - for (LogicalDevice logicalDevice : logicalDevices) { - children.put(logicalDevice.getReference().getName(), logicalDevice); - logicalDevice.setParent(this); - } + private ConnectionParam connectionParam; - if (dataSets != null) { - addDataSets(dataSets); - } + public ServerModel(List logicalDevices, Collection dataSets) { + children = new LinkedHashMap<>(); + objectReference = null; + for (LogicalDevice logicalDevice : logicalDevices) { + children.put(logicalDevice.getReference().getName(), logicalDevice); + logicalDevice.setParent(this); + } - for (LogicalDevice ld : logicalDevices) { - for (ModelNode ln : ld.getChildren()) { - for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { - urcbs.put(urcb.getReference().toString(), urcb); - urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + if (dataSets != null) { + addDataSets(dataSets); } - for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { - brcbs.put(brcb.getReference().toString(), brcb); - brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + + for (LogicalDevice ld : logicalDevices) { + for (ModelNode ln : ld.getChildren()) { + for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { + urcbs.put(urcb.getReference().toString(), urcb); + urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + } + for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { + brcbs.put(brcb.getReference().toString(), brcb); + brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + } + } } - } } - } - @Override - public ServerModel copy() { - List childCopies = new ArrayList<>(children.size()); - for (ModelNode childNode : children.values()) { - childCopies.add((LogicalDevice) childNode.copy()); + @Override + public ServerModel copy() { + List childCopies = new ArrayList<>(children.size()); + for (ModelNode childNode : children.values()) { + childCopies.add((LogicalDevice) childNode.copy()); + } + + List dataSetCopies = new ArrayList<>(dataSets.size()); + for (DataSet dataSet : dataSets.values()) { + dataSetCopies.add(dataSet); + } + + return new ServerModel(childCopies, dataSetCopies); } - List dataSetCopies = new ArrayList<>(dataSets.size()); - for (DataSet dataSet : dataSets.values()) { - dataSetCopies.add(dataSet); + /** + * Get the data set with the given reference. Return null if none is found. + * + * @param reference the reference of the requested data set. + * @return the data set with the given reference. + */ + public DataSet getDataSet(String reference) { + return dataSets.get(reference); } - return new ServerModel(childCopies, dataSetCopies); - } - - /** - * Get the data set with the given reference. Return null if none is found. - * - * @param reference the reference of the requested data set. - * @return the data set with the given reference. - */ - public DataSet getDataSet(String reference) { - return dataSets.get(reference); - } - - void addDataSet(DataSet dataSet) { - dataSets.put(dataSet.getReferenceStr().replace('$', '.'), dataSet); - for (ModelNode ld : children.values()) { - for (ModelNode ln : ld.getChildren()) { - for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { - urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + void addDataSet(DataSet dataSet) { + dataSets.put(dataSet.getReferenceStr().replace('$', '.'), dataSet); + for (ModelNode ld : children.values()) { + for (ModelNode ln : ld.getChildren()) { + for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { + urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + } + for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { + brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + } + } } - for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { - brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); - } - } } - } - void addDataSets(Collection dataSets) { - for (DataSet dataSet : dataSets) { - addDataSet(dataSet); - } - for (ModelNode ld : children.values()) { - for (ModelNode ln : ld.getChildren()) { - for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { - urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + void addDataSets(Collection dataSets) { + for (DataSet dataSet : dataSets) { + addDataSet(dataSet); } - for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { - brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + for (ModelNode ld : children.values()) { + for (ModelNode ln : ld.getChildren()) { + for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { + urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + } + for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { + brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + } + } } - } } - } - - List getDataSetNames(String ldName) { - // TODO make thread save - List dataSetNames = new ArrayList<>(); - for (String dataSetRef : dataSets.keySet()) { - if (dataSetRef.startsWith(ldName)) { - dataSetNames.add(dataSetRef.substring(dataSetRef.indexOf('/') + 1).replace('.', '$')); - } + + List getDataSetNames(String ldName) { + // TODO make thread save + List dataSetNames = new ArrayList<>(); + for (String dataSetRef : dataSets.keySet()) { + if (dataSetRef.startsWith(ldName)) { + dataSetNames.add(dataSetRef.substring(dataSetRef.indexOf('/') + 1).replace('.', '$')); + } + } + return dataSetNames; } - return dataSetNames; - } - - /** - * Get a collection of all data sets that exist in this model. - * - * @return a collection of all data sets - */ - public Collection getDataSets() { - return dataSets.values(); - } - - /** - * @param dataSetReference the data set reference - * @return returns the DataSet that was removed, null if no DataSet with the given reference was - * found or the data set is not deletable. - */ - DataSet removeDataSet(String dataSetReference) { - DataSet dataSet = dataSets.get(dataSetReference); - if (dataSet == null || !dataSet.isDeletable()) { - return null; + + /** + * Get a collection of all data sets that exist in this model. + * + * @return a collection of all data sets + */ + public Collection getDataSets() { + return dataSets.values(); } - DataSet removedDataSet = dataSets.remove(dataSetReference); - for (ModelNode ld : children.values()) { - for (ModelNode ln : ld.getChildren()) { - for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { - urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + + /** + * @param dataSetReference the data set reference + * @return returns the DataSet that was removed, null if no DataSet with the given reference was + * found or the data set is not deletable. + */ + DataSet removeDataSet(String dataSetReference) { + DataSet dataSet = dataSets.get(dataSetReference); + if (dataSet == null || !dataSet.isDeletable()) { + return null; } - for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { - brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + DataSet removedDataSet = dataSets.remove(dataSetReference); + for (ModelNode ld : children.values()) { + for (ModelNode ln : ld.getChildren()) { + for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { + urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); + } + for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { + brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); + } + } } - } - } - return removedDataSet; - } - - void addUrcb(Urcb urcb) { - urcbs.put(urcb.getReference().getName(), urcb); - } - - /** - * Get the unbuffered report control block (URCB) with the given reference. - * - * @param reference the reference of the requested URCB. - * @return the reference to the requested URCB or null if none with the given reference is found. - */ - public Urcb getUrcb(String reference) { - return urcbs.get(reference); - } - - /** - * Get a collection of all unbuffered report control blocks (URCB) that exist in this model. - * - * @return a collection of all unbuffered report control blocks (URCB) - */ - public Collection getUrcbs() { - return urcbs.values(); - } - - /** - * Get the buffered report control block (BRCB) with the given reference. - * - * @param reference the reference of the requested BRCB. - * @return the reference to the requested BRCB or null if none with the given reference is found. - */ - public Brcb getBrcb(String reference) { - return brcbs.get(reference); - } - - /** - * Get a collection of all buffered report control blocks (BRCB) that exist in this model. - * - * @return a collection of all buffered report control blocks (BRCB) - */ - public Collection getBrcbs() { - return brcbs.values(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - for (ModelNode logicalDevice : children.values()) { - sb.append(logicalDevice.toString()); + return removedDataSet; } - sb.append("\n\n\n---------------------\nURCBs:"); - for (Urcb urcb : getUrcbs()) { - sb.append("\n\n").append(urcb); + + void addUrcb(Urcb urcb) { + urcbs.put(urcb.getReference().getName(), urcb); } - sb.append("\n\n\n---------------------\nBRCBs:"); - for (Brcb brcb : getBrcbs()) { - sb.append("\n\n").append(brcb); + /** + * Get the unbuffered report control block (URCB) with the given reference. + * + * @param reference the reference of the requested URCB. + * @return the reference to the requested URCB or null if none with the given reference is found. + */ + public Urcb getUrcb(String reference) { + return urcbs.get(reference); } - sb.append("\n\n\n---------------------\nData sets:"); - for (DataSet dataSet : getDataSets()) { - sb.append("\n\n").append(dataSet); + /** + * Get a collection of all unbuffered report control blocks (URCB) that exist in this model. + * + * @return a collection of all unbuffered report control blocks (URCB) + */ + public Collection getUrcbs() { + return urcbs.values(); } - return sb.toString(); - } - - /** - * Searches and returns the model node with the given object reference and FC. If searching for - * Logical Devices and Logical Nodes the given fc parameter may be null. - * - * @param objectReference the object reference of the node that is being searched for. It has a - * syntax like "ldname/ln.do....". - * @param fc the functional constraint of the requested model node. May be null for Logical Device - * and Logical Node references. - * @return the model node if it was found or null otherwise - */ - public ModelNode findModelNode(ObjectReference objectReference, Fc fc) { - - ModelNode currentNode = this; - Iterator searchedNodeReferenceIterator = objectReference.iterator(); - - while (searchedNodeReferenceIterator.hasNext()) { - currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc); - if (currentNode == null) { - return null; - } + /** + * Get the buffered report control block (BRCB) with the given reference. + * + * @param reference the reference of the requested BRCB. + * @return the reference to the requested BRCB or null if none with the given reference is found. + */ + public Brcb getBrcb(String reference) { + return brcbs.get(reference); } - return currentNode; - } - - /** - * Searches and returns the model node with the given object reference and FC. If searching for - * Logical Devices and Logical Nodes the given fc parameter may be null. - * - * @param objectReference the object reference of the node that is being searched for. It has a - * syntax like "ldname/ln.do....". - * @param fc the functional constraint of the requested model node. May be null for Logical Device - * and Logical Node references. - * @return the model node if it was found or null otherwise - */ - public ModelNode findModelNode(String objectReference, Fc fc) { - return findModelNode(new ObjectReference(objectReference), fc); - } - - /** - * Returns the subModelNode that is referenced by the given VariableDef. Return null in case the - * referenced ModelNode is not found. - * - * @param variableDef the variableDef - * @return the subModelNode that is referenced by the given VariableDef - * @throws ServiceError if an error occurs - */ - FcModelNode getNodeFromVariableDef(VariableDefs.SEQUENCE variableDef) throws ServiceError { - - ObjectName objectName = variableDef.getVariableSpecification().getName(); - - if (objectName == null) { - throw new ServiceError( - ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, - "name in objectName is not selected"); + + /** + * Get a collection of all buffered report control blocks (BRCB) that exist in this model. + * + * @return a collection of all buffered report control blocks (BRCB) + */ + public Collection getBrcbs() { + return brcbs.values(); } - DomainSpecific domainSpecific = objectName.getDomainSpecific(); + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (ModelNode logicalDevice : children.values()) { + sb.append(logicalDevice.toString()); + } + sb.append("\n\n\n---------------------\nURCBs:"); + for (Urcb urcb : getUrcbs()) { + sb.append("\n\n").append(urcb); + } - if (domainSpecific == null) { - throw new ServiceError( - ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, - "domain_specific in name is not selected"); - } + sb.append("\n\n\n---------------------\nBRCBs:"); + for (Brcb brcb : getBrcbs()) { + sb.append("\n\n").append(brcb); + } - ModelNode modelNode = getChild(domainSpecific.getDomainID().toString()); + sb.append("\n\n\n---------------------\nData sets:"); + for (DataSet dataSet : getDataSets()) { + sb.append("\n\n").append(dataSet); + } - if (modelNode == null) { - return null; + return sb.toString(); } - String mmsItemId = domainSpecific.getItemID().toString(); - int index1 = mmsItemId.indexOf('$'); + /** + * Searches and returns the model node with the given object reference and FC. If searching for + * Logical Devices and Logical Nodes the given fc parameter may be null. + * + * @param objectReference the object reference of the node that is being searched for. It has a + * syntax like "ldname/ln.do....". + * @param fc the functional constraint of the requested model node. May be null for Logical Device + * and Logical Node references. + * @return the model node if it was found or null otherwise + */ + public ModelNode findModelNode(ObjectReference objectReference, Fc fc) { + + ModelNode currentNode = this; + Iterator searchedNodeReferenceIterator = objectReference.iterator(); + + while (searchedNodeReferenceIterator.hasNext()) { + currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc); + if (currentNode == null) { + return null; + } + } + return currentNode; + } - if (index1 == -1) { - throw new ServiceError( - ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, - "invalid mms item id: " + domainSpecific.getItemID()); + /** + * Searches and returns the model node with the given object reference and FC. If searching for + * Logical Devices and Logical Nodes the given fc parameter may be null. + * + * @param objectReference the object reference of the node that is being searched for. It has a + * syntax like "ldname/ln.do....". + * @param fc the functional constraint of the requested model node. May be null for Logical Device + * and Logical Node references. + * @return the model node if it was found or null otherwise + */ + public ModelNode findModelNode(String objectReference, Fc fc) { + return findModelNode(new ObjectReference(objectReference), fc); } - LogicalNode ln = (LogicalNode) modelNode.getChild(mmsItemId.substring(0, index1)); + /** + * Returns the subModelNode that is referenced by the given VariableDef. Return null in case the + * referenced ModelNode is not found. + * + * @param variableDef the variableDef + * @return the subModelNode that is referenced by the given VariableDef + * @throws ServiceError if an error occurs + */ + FcModelNode getNodeFromVariableDef(VariableDefs.SEQUENCE variableDef) throws ServiceError { + + ObjectName objectName = variableDef.getVariableSpecification().getName(); + + if (objectName == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "name in objectName is not selected"); + } - if (ln == null) { - return null; - } + DomainSpecific domainSpecific = objectName.getDomainSpecific(); + + if (domainSpecific == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "domain_specific in name is not selected"); + } - int index2 = mmsItemId.indexOf('$', index1 + 1); + ModelNode modelNode = getChild(domainSpecific.getDomainID().toString()); - if (index2 == -1) { - throw new ServiceError( - ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id"); - } + if (modelNode == null) { + return null; + } - Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2)); + String mmsItemId = domainSpecific.getItemID().toString(); + int index1 = mmsItemId.indexOf('$'); - if (fc == null) { - throw new ServiceError( - ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, - "unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2)); - } + if (index1 == -1) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "invalid mms item id: " + domainSpecific.getItemID()); + } - index1 = index2; + LogicalNode ln = (LogicalNode) modelNode.getChild(mmsItemId.substring(0, index1)); - index2 = mmsItemId.indexOf('$', index1 + 1); + if (ln == null) { + return null; + } - if (index2 == -1) { - if (fc == Fc.RP) { - return ln.getUrcb(mmsItemId.substring(index1 + 1)); - } - if (fc == Fc.BR) { - return ln.getBrcb(mmsItemId.substring(index1 + 1)); - } - return (FcModelNode) ln.getChild(mmsItemId.substring(index1 + 1), fc); - } + int index2 = mmsItemId.indexOf('$', index1 + 1); - if (fc == Fc.RP) { - modelNode = ln.getUrcb(mmsItemId.substring(index1 + 1, index2)); - } else if (fc == Fc.BR) { - modelNode = ln.getBrcb(mmsItemId.substring(index1 + 1, index2)); - } else { - modelNode = ln.getChild(mmsItemId.substring(index1 + 1, index2), fc); - } + if (index2 == -1) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id"); + } - index1 = index2; - index2 = mmsItemId.indexOf('$', index1 + 1); - while (index2 != -1) { - modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1, index2)); - index1 = index2; - index2 = mmsItemId.indexOf('$', index1 + 1); - } + Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2)); - modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1)); + if (fc == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2)); + } - if (variableDef.getAlternateAccess() == null) { - // no array is in this node path - return (FcModelNode) modelNode; - } + index1 = index2; + + index2 = mmsItemId.indexOf('$', index1 + 1); + + if (index2 == -1) { + if (fc == Fc.RP) { + return ln.getUrcb(mmsItemId.substring(index1 + 1)); + } + if (fc == Fc.BR) { + return ln.getBrcb(mmsItemId.substring(index1 + 1)); + } + return (FcModelNode) ln.getChild(mmsItemId.substring(index1 + 1), fc); + } + + if (fc == Fc.RP) { + modelNode = ln.getUrcb(mmsItemId.substring(index1 + 1, index2)); + } else if (fc == Fc.BR) { + modelNode = ln.getBrcb(mmsItemId.substring(index1 + 1, index2)); + } else { + modelNode = ln.getChild(mmsItemId.substring(index1 + 1, index2), fc); + } - AlternateAccessSelection altAccIt = - variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed(); - - if (altAccIt.getSelectAlternateAccess() != null) { - // path to node below an array element - modelNode = - ((Array) modelNode) - .getChild( - altAccIt.getSelectAlternateAccess().getAccessSelection().getIndex().intValue()); - - String mmsSubArrayItemId = - altAccIt - .getSelectAlternateAccess() - .getAlternateAccess() - .getCHOICE() - .get(0) - .getUnnamed() - .getSelectAccess() - .getComponent() - .getBasic() - .toString(); - - index1 = -1; - index2 = mmsSubArrayItemId.indexOf('$'); - while (index2 != -1) { - modelNode = modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1, index2)); index1 = index2; index2 = mmsItemId.indexOf('$', index1 + 1); - } + while (index2 != -1) { + modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1, index2)); + index1 = index2; + index2 = mmsItemId.indexOf('$', index1 + 1); + } + + modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1)); + + if (variableDef.getAlternateAccess() == null) { + // no array is in this node path + return (FcModelNode) modelNode; + } + + AlternateAccessSelection altAccIt = + variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed(); + + if (altAccIt.getSelectAlternateAccess() != null) { + // path to node below an array element + modelNode = + ((Array) modelNode) + .getChild( + altAccIt.getSelectAlternateAccess().getAccessSelection().getIndex().intValue()); + + String mmsSubArrayItemId = + altAccIt + .getSelectAlternateAccess() + .getAlternateAccess() + .getCHOICE() + .get(0) + .getUnnamed() + .getSelectAccess() + .getComponent() + .getBasic() + .toString(); + + index1 = -1; + index2 = mmsSubArrayItemId.indexOf('$'); + while (index2 != -1) { + modelNode = modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1, index2)); + index1 = index2; + index2 = mmsItemId.indexOf('$', index1 + 1); + } + + return (FcModelNode) modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1)); + } else { + // path to an array element + return (FcModelNode) + ((Array) modelNode).getChild(altAccIt.getSelectAccess().getIndex().intValue()); + } + } + + public ConnectionParam getConnectionParam() { + return connectionParam; + } - return (FcModelNode) modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1)); - } else { - // path to an array element - return (FcModelNode) - ((Array) modelNode).getChild(altAccIt.getSelectAccess().getIndex().intValue()); + public void setConnectionParam(ConnectionParam connectionParam) { + this.connectionParam = connectionParam; } - } -} +} \ No newline at end of file