|
|
|
@ -13,34 +13,20 @@
|
|
|
|
|
*/
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
|
|
|
|
|
|
|
|
public class SclParser {
|
|
|
|
|
|
|
|
|
|
private final Map<String, DataSet> dataSetsMap = new HashMap<>();
|
|
|
|
@ -48,10 +34,15 @@ public class SclParser {
|
|
|
|
|
private TypeDefinitions typeDefinitions;
|
|
|
|
|
private Document doc;
|
|
|
|
|
private String iedName;
|
|
|
|
|
private List<ServerModel> serverModels = new ArrayList<>();
|
|
|
|
|
private final List<ServerModel> serverModels = new ArrayList<>();
|
|
|
|
|
private boolean useResvTmsAttributes = false;
|
|
|
|
|
|
|
|
|
|
private SclParser() {}
|
|
|
|
|
private String iedConnectedAP;
|
|
|
|
|
ConnectionParam connectionParm;
|
|
|
|
|
private final Map<String, ConnectionParam> iedConnectionMap = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
private SclParser() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static List<ServerModel> parse(InputStream is) throws SclParseException {
|
|
|
|
|
SclParser sclParser = new SclParser();
|
|
|
|
@ -88,6 +79,39 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
readTypeDefinitions();
|
|
|
|
|
|
|
|
|
|
NodeList connectedAPs = doc.getElementsByTagName("ConnectedAP");
|
|
|
|
|
|
|
|
|
|
for (int zz = 0; zz < connectedAPs.getLength(); zz++) {
|
|
|
|
|
Node connectedAP = connectedAPs.item(zz);
|
|
|
|
|
Node attributeName = connectedAP.getAttributes().getNamedItem("iedName");
|
|
|
|
|
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 iedList = doc.getElementsByTagName("IED");
|
|
|
|
|
if (iedList.getLength() == 0) {
|
|
|
|
|
throw new SclParseException("No IED section found!");
|
|
|
|
@ -131,6 +155,48 @@ public class SclParser {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void readTypeDefinitions() throws SclParseException {
|
|
|
|
|
|
|
|
|
|
NodeList dttSections = doc.getElementsByTagName("DataTypeTemplates");
|
|
|
|
@ -148,14 +214,19 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
String nodeName = element.getNodeName();
|
|
|
|
|
|
|
|
|
|
if (nodeName.equals("LNodeType")) {
|
|
|
|
|
switch (nodeName) {
|
|
|
|
|
case "LNodeType":
|
|
|
|
|
typeDefinitions.putLNodeType(new LnType(element));
|
|
|
|
|
} else if (nodeName.equals("DOType")) {
|
|
|
|
|
break;
|
|
|
|
|
case "DOType":
|
|
|
|
|
typeDefinitions.putDOType(new DoType(element));
|
|
|
|
|
} else if (nodeName.equals("DAType")) {
|
|
|
|
|
break;
|
|
|
|
|
case "DAType":
|
|
|
|
|
typeDefinitions.putDAType(new DaType(element));
|
|
|
|
|
} else if (nodeName.equals("EnumType")) {
|
|
|
|
|
break;
|
|
|
|
|
case "EnumType":
|
|
|
|
|
typeDefinitions.putEnumType(new EnumType(element));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -212,6 +283,8 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
dataSetDefs.clear();
|
|
|
|
|
|
|
|
|
|
serverModel.setConnectionParam(iedConnectionMap.get(iedName));
|
|
|
|
|
|
|
|
|
|
return serverModel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -378,25 +451,33 @@ public class SclParser {
|
|
|
|
|
Node node = attributes.item(j);
|
|
|
|
|
String nodeName = node.getNodeName();
|
|
|
|
|
|
|
|
|
|
if (nodeName.equals("ldInst")) {
|
|
|
|
|
switch (nodeName) {
|
|
|
|
|
case "ldInst":
|
|
|
|
|
ldInst = node.getNodeValue();
|
|
|
|
|
} else if (nodeName.equals("lnInst")) {
|
|
|
|
|
break;
|
|
|
|
|
case "lnInst":
|
|
|
|
|
lnInst = node.getNodeValue();
|
|
|
|
|
} else if (nodeName.equals("lnClass")) {
|
|
|
|
|
break;
|
|
|
|
|
case "lnClass":
|
|
|
|
|
lnClass = node.getNodeValue();
|
|
|
|
|
} else if (nodeName.equals("prefix")) {
|
|
|
|
|
break;
|
|
|
|
|
case "prefix":
|
|
|
|
|
prefix = node.getNodeValue();
|
|
|
|
|
} else if (nodeName.equals("doName")) {
|
|
|
|
|
break;
|
|
|
|
|
case "doName":
|
|
|
|
|
doName = node.getNodeValue();
|
|
|
|
|
} else if (nodeName.equals("daName")) {
|
|
|
|
|
break;
|
|
|
|
|
case "daName":
|
|
|
|
|
if (!node.getNodeValue().isEmpty()) {
|
|
|
|
|
daName = "." + node.getNodeValue();
|
|
|
|
|
}
|
|
|
|
|
} else if (nodeName.equals("fc")) {
|
|
|
|
|
break;
|
|
|
|
|
case "fc":
|
|
|
|
|
fc = Fc.fromString(node.getNodeValue());
|
|
|
|
|
if (fc == null) {
|
|
|
|
|
throw new SclParseException("FCDA contains invalid FC: " + node.getNodeValue());
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -588,7 +669,7 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
BdaVisibleString rptId =
|
|
|
|
|
new BdaVisibleString(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".RptID"), fc, "", 129, false, false);
|
|
|
|
|
new ObjectReference(reportObjRef + ".RptID"), fc, "", 129, false, false);
|
|
|
|
|
attribute = rcbNodeAttributes.getNamedItem("rptID");
|
|
|
|
|
if (attribute != null) {
|
|
|
|
|
rptId.setValue(attribute.getNodeValue().getBytes(UTF_8));
|
|
|
|
@ -600,17 +681,17 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaBoolean(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".RptEna"), fc, "", false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".RptEna"), fc, "", false, false));
|
|
|
|
|
|
|
|
|
|
if (fc == Fc.RP) {
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaBoolean(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".Resv"), fc, "", false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".Resv"), fc, "", false, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BdaVisibleString datSet =
|
|
|
|
|
new BdaVisibleString(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".DatSet"), fc, "", 129, false, false);
|
|
|
|
|
new ObjectReference(reportObjRef + ".DatSet"), fc, "", 129, false, false);
|
|
|
|
|
|
|
|
|
|
attribute = xmlNode.getAttributes().getNamedItem("datSet");
|
|
|
|
|
if (attribute != null) {
|
|
|
|
@ -622,7 +703,7 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
BdaInt32U confRef =
|
|
|
|
|
new BdaInt32U(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".ConfRev"), fc, "", false, false);
|
|
|
|
|
new ObjectReference(reportObjRef + ".ConfRev"), fc, "", false, false);
|
|
|
|
|
attribute = xmlNode.getAttributes().getNamedItem("confRev");
|
|
|
|
|
if (attribute == null) {
|
|
|
|
|
throw new SclParseException(
|
|
|
|
@ -635,7 +716,7 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
BdaInt32U bufTm =
|
|
|
|
|
new BdaInt32U(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".BufTm"), fc, "", false, false);
|
|
|
|
|
new ObjectReference(reportObjRef + ".BufTm"), fc, "", false, false);
|
|
|
|
|
attribute = xmlNode.getAttributes().getNamedItem("bufTime");
|
|
|
|
|
if (attribute != null) {
|
|
|
|
|
bufTm.setValue(Long.parseLong(attribute.getNodeValue()));
|
|
|
|
@ -644,13 +725,13 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaInt8U(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".SqNum"), fc, "", false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".SqNum"), fc, "", false, false));
|
|
|
|
|
|
|
|
|
|
children.add(trigOps);
|
|
|
|
|
|
|
|
|
|
BdaInt32U intgPd =
|
|
|
|
|
new BdaInt32U(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".IntgPd"), fc, "", false, false);
|
|
|
|
|
new ObjectReference(reportObjRef + ".IntgPd"), fc, "", false, false);
|
|
|
|
|
attribute = xmlNode.getAttributes().getNamedItem("intgPd");
|
|
|
|
|
if (attribute != null) {
|
|
|
|
|
intgPd.setValue(Long.parseLong(attribute.getNodeValue()));
|
|
|
|
@ -659,19 +740,19 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaBoolean(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".GI"), fc, "", false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".GI"), fc, "", false, false));
|
|
|
|
|
|
|
|
|
|
Rcb rcb = null;
|
|
|
|
|
Rcb rcb;
|
|
|
|
|
|
|
|
|
|
if (fc == Fc.BR) {
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaBoolean(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".PurgeBuf"), fc, "", false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".PurgeBuf"), fc, "", false, false));
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaOctetString(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".EntryID"),
|
|
|
|
|
new ObjectReference(reportObjRef + ".EntryID"),
|
|
|
|
|
fc,
|
|
|
|
|
"",
|
|
|
|
|
8,
|
|
|
|
@ -680,7 +761,7 @@ public class SclParser {
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaEntryTime(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".TimeOfEntry"),
|
|
|
|
|
new ObjectReference(reportObjRef + ".TimeOfEntry"),
|
|
|
|
|
fc,
|
|
|
|
|
"",
|
|
|
|
|
false,
|
|
|
|
@ -689,19 +770,19 @@ public class SclParser {
|
|
|
|
|
if (useResvTmsAttributes) {
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaInt16(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".ResvTms"), fc, "", false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".ResvTms"), fc, "", false, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaOctetString(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".Owner"), fc, "", 64, false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".Owner"), fc, "", 64, false, false));
|
|
|
|
|
|
|
|
|
|
rcb = new Brcb(reportObjRef, children);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
children.add(
|
|
|
|
|
new BdaOctetString(
|
|
|
|
|
new ObjectReference(reportObjRef.toString() + ".Owner"), fc, "", 64, false, false));
|
|
|
|
|
new ObjectReference(reportObjRef + ".Owner"), fc, "", 64, false, false));
|
|
|
|
|
|
|
|
|
|
rcb = new Urcb(reportObjRef, children);
|
|
|
|
|
}
|
|
|
|
@ -821,7 +902,9 @@ public class SclParser {
|
|
|
|
|
return new Array(new ObjectReference(ref), fc, arrayItems);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** returns a ConstructedDataAttribute or BasicDataAttribute */
|
|
|
|
|
/**
|
|
|
|
|
* returns a ConstructedDataAttribute or BasicDataAttribute
|
|
|
|
|
*/
|
|
|
|
|
private FcModelNode createDataAttribute(
|
|
|
|
|
String ref,
|
|
|
|
|
Fc fc,
|
|
|
|
|