From 95ee0d5f2b5ea882aed5684416cb63ef11e3910d Mon Sep 17 00:00:00 2001
From: massifben <105049157+massifben@users.noreply.github.com>
Date: Wed, 6 Dec 2023 11:58:21 +0100
Subject: [PATCH] feat(#362): RSR-812 - Use generated JAXB class for
configuration of Communication of Control Blocks
Signed-off-by: massifben <105049157+massifben@users.noreply.github.com>
---
.../SclAutomationServiceIntegrationTest.java | 5 +-
sct-commons/pom.xml | 19 +-
.../commons/ControlBlockEditorService.java | 430 ++++++++++++++++++
.../sct/commons/ControlBlockService.java | 159 -------
.../sct/commons/api/ControlBlockEditor.java | 16 +-
.../dto/ControlBlockNetworkSettings.java | 71 ---
.../sct/commons/scl/ControlService.java | 26 ++
.../commons/scl/ied/ControlBlockAdapter.java | 80 ----
.../sct/commons/util/ControlBlockEnum.java | 24 +-
.../ControlBlockNetworkSettingsCsvHelper.java | 204 ---------
.../src/main/resources/xsd/GSE_SMV_CB_COM.xsd | 152 +++++++
.../{LDEPF_Config_file_v2.xsd => LDEPF.xsd} | 0
...ava => ControlBlockEditorServiceTest.java} | 416 ++++++++++++-----
.../dto/ControlBlockNetworkSettingsTest.java | 235 ----------
.../scl/ied/ControlBlockAdapterTest.java | 87 +---
.../commons/util/ControlBlockEnumTest.java | 41 +-
.../ControlBlockCommunicationTemplates.csv | 9 -
17 files changed, 995 insertions(+), 979 deletions(-)
create mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockEditorService.java
delete mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockService.java
delete mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettings.java
create mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ControlService.java
delete mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockNetworkSettingsCsvHelper.java
create mode 100644 sct-commons/src/main/resources/xsd/GSE_SMV_CB_COM.xsd
rename sct-commons/src/main/resources/xsd/{LDEPF_Config_file_v2.xsd => LDEPF.xsd} (100%)
rename sct-commons/src/test/java/org/lfenergy/compas/sct/commons/{ControlBlockServiceTest.java => ControlBlockEditorServiceTest.java} (52%)
delete mode 100644 sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettingsTest.java
delete mode 100644 sct-commons/src/test/resources/ControlBlockCommunicationTemplates.csv
diff --git a/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceIntegrationTest.java b/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceIntegrationTest.java
index d4aaea1ca..d2e8bd735 100644
--- a/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceIntegrationTest.java
+++ b/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceIntegrationTest.java
@@ -8,7 +8,7 @@
import org.junit.jupiter.api.Test;
import org.lfenergy.compas.scl2007b4.model.LN0;
import org.lfenergy.compas.scl2007b4.model.SCL;
-import org.lfenergy.compas.sct.commons.ControlBlockService;
+import org.lfenergy.compas.sct.commons.ControlBlockEditorService;
import org.lfenergy.compas.sct.commons.SclService;
import org.lfenergy.compas.sct.commons.SubstationService;
import org.lfenergy.compas.sct.commons.api.ControlBlockEditor;
@@ -16,6 +16,7 @@
import org.lfenergy.compas.sct.commons.api.SubstationEditor;
import org.lfenergy.compas.sct.commons.dto.HeaderDTO;
import org.lfenergy.compas.sct.commons.exception.ScdException;
+import org.lfenergy.compas.sct.commons.scl.ControlService;
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
@@ -33,7 +34,7 @@ class SclAutomationServiceIntegrationTest {
private SclAutomationService sclAutomationService ;
private static final SclEditor sclEditor = new SclService() ;
private static final SubstationEditor substationEditor = new SubstationService() ;
- private static final ControlBlockEditor controlBlockEditor = new ControlBlockService() ;
+ private static final ControlBlockEditor controlBlockEditor = new ControlBlockEditorService(new ControlService()) ;
private HeaderDTO headerDTO;
diff --git a/sct-commons/pom.xml b/sct-commons/pom.xml
index c807d1237..285b507b1 100644
--- a/sct-commons/pom.xml
+++ b/sct-commons/pom.xml
@@ -185,7 +185,7 @@
-
+
${project.basedir}/src/main/resources/binding_configuration.xjb
@@ -214,6 +214,23 @@
false
+
+ cbcom
+
+ xjc
+
+
+
+
+
+
+ ${project.basedir}/src/main/resources/binding_configuration.xjb
+
+ org.lfenergy.compas.sct.commons.model.cbcom
+ true
+ false
+
+
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockEditorService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockEditorService.java
new file mode 100644
index 000000000..9f01aa8ec
--- /dev/null
+++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockEditorService.java
@@ -0,0 +1,430 @@
+// SPDX-FileCopyrightText: 2022 2023 RTE FRANCE
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package org.lfenergy.compas.sct.commons;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.lfenergy.compas.scl2007b4.model.*;
+import org.lfenergy.compas.sct.commons.api.ControlBlockEditor;
+import org.lfenergy.compas.sct.commons.dto.FcdaForDataSetsCreation;
+import org.lfenergy.compas.sct.commons.dto.SclReportItem;
+import org.lfenergy.compas.sct.commons.exception.ScdException;
+import org.lfenergy.compas.sct.commons.model.cbcom.*;
+import org.lfenergy.compas.sct.commons.scl.ControlService;
+import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
+import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
+import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
+import org.lfenergy.compas.sct.commons.scl.ln.LNAdapter;
+import org.lfenergy.compas.sct.commons.util.ControlBlockEnum;
+import org.lfenergy.compas.sct.commons.util.PrivateUtils;
+import org.lfenergy.compas.sct.commons.util.SclConstructorHelper;
+import org.lfenergy.compas.sct.commons.util.Utils;
+
+import java.math.BigInteger;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newAddress;
+import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newP;
+
+@RequiredArgsConstructor
+public class ControlBlockEditorService implements ControlBlockEditor {
+
+ private static final int MAX_VLAN_ID = 0x0FFF;
+ private static final int MAX_VLAN_PRIORITY = 7;
+ private static final String NONE = "none";
+ private static final String APPID_P_TYPE = "APPID";
+ private static final String MAC_ADDRESS_P_TYPE = "MAC-Address";
+ private static final String VLAN_ID_P_TYPE = "VLAN-ID";
+ private static final String VLAN_PRIORITY_P_TYPE = "VLAN-PRIORITY";
+ private static final int APPID_LENGTH = 4;
+ private static final int VLAN_ID_LENGTH = 3;
+ private static final String MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM = "Error in Control Block communication setting file: vlan is missing attribute ";
+ private final ControlService controlService;
+
+ @Override
+ public List analyzeDataGroups(SCL scd) {
+ SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
+ return sclRootAdapter.streamIEDAdapters()
+ .map(iedAdapter -> {
+ List list = new ArrayList<>();
+ list.addAll(iedAdapter.checkDataGroupCoherence());
+ list.addAll(iedAdapter.checkBindingDataGroupCoherence());
+ return list;
+ }).flatMap(Collection::stream).toList();
+ }
+
+ @Override
+ public List createDataSetAndControlBlocks(SCL scd, Set allowedFcdas) {
+ checkFcdaInitDataPresence(allowedFcdas);
+ SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
+ Stream lDeviceAdapters = sclRootAdapter.streamIEDAdapters().flatMap(IEDAdapter::streamLDeviceAdapters);
+ return createDataSetAndControlBlocks(lDeviceAdapters, allowedFcdas);
+ }
+
+ @Override
+ public List createDataSetAndControlBlocks(SCL scd, String targetIedName, Set allowedFcdas) {
+ checkFcdaInitDataPresence(allowedFcdas);
+ SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
+ IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
+ return createDataSetAndControlBlocks(iedAdapter.streamLDeviceAdapters(), allowedFcdas);
+
+ }
+
+ @Override
+ public List createDataSetAndControlBlocks(SCL scd, String targetIedName, String targetLDeviceInst, Set allowedFcdas) {
+ requireNotBlank(targetIedName, "IED.name parameter is missing");
+ checkFcdaInitDataPresence(allowedFcdas);
+ SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
+ IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
+ LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(targetLDeviceInst);
+ return createDataSetAndControlBlocks(Stream.of(lDeviceAdapter), allowedFcdas);
+ }
+
+ private void checkFcdaInitDataPresence(Set allowedFcdas) {
+ if (allowedFcdas == null || allowedFcdas.isEmpty()) {
+ throw new ScdException("Accepted FCDAs list is empty, you should initialize allowed FCDA lists with CsvHelper class before");
+ }
+ }
+
+ private List createDataSetAndControlBlocks(Stream lDeviceAdapters, Set allowedFcdas) {
+ return lDeviceAdapters
+ .map(lDeviceAdapter -> lDeviceAdapter.createDataSetAndControlBlocks(allowedFcdas))
+ .flatMap(List::stream)
+ .toList();
+ }
+
+ @Override
+ public void removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(final SCL scl) {
+ SclRootAdapter sclRootAdapter = new SclRootAdapter(scl);
+ List lDeviceAdapters = sclRootAdapter.streamIEDAdapters()
+ .flatMap(IEDAdapter::streamLDeviceAdapters).toList();
+ // LN0
+ lDeviceAdapters.stream()
+ .map(LDeviceAdapter::getLN0Adapter)
+ .forEach(ln0 -> {
+ ln0.removeAllControlBlocksAndDatasets();
+ ln0.removeAllExtRefSourceBindings();
+ });
+ // Other LN
+ lDeviceAdapters.stream()
+ .map(LDeviceAdapter::getLNAdapters).flatMap(List::stream)
+ .forEach(LNAdapter::removeAllControlBlocksAndDatasets);
+ }
+
+ @Override
+ public List configureNetworkForAllControlBlocks(SCL scd, CBCom cbCom) {
+ return Stream.concat(
+ configureNetworkForControlBlocks(scd, cbCom, TCBType.GOOSE),
+ configureNetworkForControlBlocks(scd, cbCom, TCBType.SV))
+ .toList();
+ }
+
+ private Stream configureNetworkForControlBlocks(SCL scl, CBCom cbCom, TCBType tcbType) {
+ CbComSettings cbComSettings;
+ try {
+ cbComSettings = parseCbCom(cbCom, tcbType);
+ } catch (ScdException ex) {
+ return Stream.of(SclReportItem.error("Control Block Communication setting files", ex.getMessage()));
+ }
+ return scl.getIED().stream()
+ .flatMap(tied ->
+ tied.getAccessPoint()
+ .stream()
+ .filter(tAccessPoint -> tAccessPoint.isSetServer() && tAccessPoint.getServer().isSetLDevice())
+ .flatMap(tAccessPoint -> tAccessPoint.getServer().getLDevice().stream()
+ .map(tlDevice -> new IedApLd(tied, tAccessPoint.getName(), tlDevice))
+ )
+ )
+ .flatMap(iedApLd -> Optional.ofNullable(iedApLd.lDevice().getLN0()).stream()
+ .flatMap(ln0 -> controlService.getControls(ln0, ControlBlockEnum.from(tcbType).getControlBlockClass()))
+ .map(tControl -> {
+ CriteriaOrError criteriaOrError = getCriteria(iedApLd.ied(), tcbType, tControl.getName());
+ if (criteriaOrError.errorMessage != null) {
+ return Optional.of(SclReportItem.error(iedApLd.getXPath(), criteriaOrError.errorMessage));
+ }
+ Settings settings = cbComSettings.settingsByCriteria.get(criteriaOrError.criteria);
+ if (settings == null) {
+ return newError(iedApLd, tControl, "Cannot configure communication for this ControlBlock because: No controlBlock communication settings found with these " + criteriaOrError.criteria);
+ }
+ return configureControlBlockNetwork(scl.getCommunication(), settings, cbComSettings.appIdIterator, cbComSettings.macAddressIterator, tControl, iedApLd);
+ })
+ .flatMap(Optional::stream)
+ );
+ }
+
+ private CbComSettings parseCbCom(CBCom cbCom, TCBType tcbType) {
+ TRange appIdRange = Optional.ofNullable(cbCom.getAppIdRanges()).map(AppIdRanges::getAppIdRange).stream()
+ .flatMap(Collection::stream)
+ .filter(tRange -> tcbType.equals(tRange.getCBType()))
+ .findFirst()
+ .orElseThrow(() -> new ScdException("Control Block Communication setting files does not contain AppIdRange for cbType " + tcbType.value()));
+ PrimitiveIterator.OfLong appIdIterator = Utils.sequence(Long.parseLong(appIdRange.getStart(), 16), Long.parseLong(appIdRange.getEnd(), 16));
+
+ TRange macRange = Optional.ofNullable(cbCom.getMacRanges()).map(MacRanges::getMacRange).stream()
+ .flatMap(Collection::stream)
+ .filter(tRange -> tcbType.equals(tRange.getCBType()))
+ .findFirst()
+ .orElseThrow(() -> new ScdException("Control Block Communication setting files does not contain MacRange for cbType " + tcbType.value()));
+ Iterator macAddressIterator = Utils.macAddressSequence(macRange.getStart(), macRange.getEnd());
+
+ Map settingsByCriteria = Optional.ofNullable(cbCom.getVlans()).map(Vlans::getVlan).stream()
+ .flatMap(Collection::stream)
+ .filter(vlan -> tcbType.equals(vlan.getCBType()))
+ .collect(Collectors.toMap(this::vlanToCriteria, this::vlanToSetting));
+
+ return new CbComSettings(appIdIterator, macAddressIterator, settingsByCriteria);
+ }
+
+ private Optional configureControlBlockNetwork(TCommunication tCommunication, Settings settings, PrimitiveIterator.OfLong appIdIterator, Iterator macAddressIterator, TControl tControl, IedApLd iedApLd) {
+ if (settings.vlanId() == null) {
+ return newError(iedApLd, tControl, "Cannot configure communication for this ControlBlock because no Vlan Id was provided in the settings");
+ }
+ if (!appIdIterator.hasNext()) {
+ return newError(iedApLd, tControl, "Cannot configure communication for this ControlBlock because range of appId is exhausted");
+ }
+ if (!macAddressIterator.hasNext()) {
+ return newError(iedApLd, tControl, "Cannot configure communication for this ControlBlock because range of MAC Address is exhausted");
+ }
+
+ Optional optConApAdapter = findConnectedAp(tCommunication, iedApLd.ied.getName(), iedApLd.apName);
+ if (optConApAdapter.isEmpty()) {
+ return newError(iedApLd, tControl, "Cannot configure communication for ControlBlock because no ConnectedAP found for AccessPoint");
+ }
+ TConnectedAP tConnectedAP = optConApAdapter.get();
+ List listOfPs = new ArrayList<>();
+ listOfPs.add(newP(APPID_P_TYPE, Utils.toHex(appIdIterator.nextLong(), APPID_LENGTH)));
+ listOfPs.add(newP(MAC_ADDRESS_P_TYPE, macAddressIterator.next()));
+ listOfPs.add(newP(VLAN_ID_P_TYPE, Utils.toHex(settings.vlanId(), VLAN_ID_LENGTH)));
+ if (settings.vlanPriority() != null) {
+ listOfPs.add(newP(VLAN_PRIORITY_P_TYPE, String.valueOf(settings.vlanPriority())));
+ }
+
+ switch (tControl) {
+ case TGSEControl ignored -> updateGseOrCreateIfNotExists(tConnectedAP, iedApLd.lDevice().getInst(), tControl.getName(), listOfPs, SclConstructorHelper.newDurationInMilliSec(settings.minTime), SclConstructorHelper.newDurationInMilliSec(settings.maxTime));
+ case TSampledValueControl ignored -> updateSmvOrCreateIfNotExists(tConnectedAP, iedApLd.lDevice().getInst(), tControl.getName(), listOfPs);
+ default -> throw new ScdException("Unsupported Control Block type for communication configuration : " + tControl.getClass().getName());
+ }
+ return Optional.empty();
+ }
+
+ private Optional findConnectedAp(TCommunication tCommunication, String iedName, String apName) {
+ if (tCommunication == null || !tCommunication.isSetSubNetwork()) {
+ return Optional.empty();
+ }
+ return tCommunication.getSubNetwork().stream()
+ .filter(TSubNetwork::isSetConnectedAP)
+ .flatMap(tSubNetwork -> tSubNetwork.getConnectedAP().stream())
+ .filter(tConnectedAP -> iedName.equals(tConnectedAP.getIedName()) && apName.equals(tConnectedAP.getApName()))
+ .findFirst();
+ }
+
+ private void updateGseOrCreateIfNotExists(TConnectedAP tConnectedAP, String ldInst, String cbName, List listOfP, TDurationInMilliSec minTime, TDurationInMilliSec maxTime) {
+ Optional optGse = tConnectedAP.isSetGSE() ?
+ tConnectedAP.getGSE().stream().filter(gse1 -> Objects.equals(ldInst, gse1.getLdInst()) && Objects.equals(cbName, gse1.getCbName())).findFirst()
+ : Optional.empty();
+ TGSE gse = optGse
+ .orElseGet(() -> {
+ TGSE newGse = new TGSE();
+ newGse.setLdInst(ldInst);
+ newGse.setCbName(cbName);
+ tConnectedAP.getGSE().add(newGse);
+ return newGse;
+ }
+ );
+ gse.setAddress(newAddress(listOfP));
+ gse.setMinTime(minTime);
+ gse.setMaxTime(maxTime);
+ }
+
+ /**
+ * Create A SMV Section or update an existing SMV Section (the network configuration of a SampledValueControl block)..
+ */
+ private void updateSmvOrCreateIfNotExists(TConnectedAP tConnectedAP, String ldInst, String cbName, List listOfP) {
+ Optional optSmv = tConnectedAP.isSetSMV() ?
+ tConnectedAP.getSMV().stream().filter(smv1 -> Objects.equals(ldInst, smv1.getLdInst()) && Objects.equals(cbName, smv1.getCbName())).findFirst()
+ : Optional.empty();
+ TSMV smv = optSmv
+ .orElseGet(() -> {
+ TSMV newSmv = new TSMV();
+ newSmv.setLdInst(ldInst);
+ newSmv.setCbName(cbName);
+ tConnectedAP.getSMV().add(newSmv);
+ return newSmv;
+ }
+ );
+ smv.setAddress(newAddress(listOfP));
+ }
+
+ private static Optional newError(IedApLd iedApLd, TControl tControl, String message) {
+ return Optional.of(SclReportItem.error(iedApLd.getXPath() + "/LN0/" + controlBlockXPath(tControl),
+ message));
+ }
+
+ private static String controlBlockXPath(TControl tControl) {
+ return ControlBlockEnum.from(tControl.getClass()).getElementName() + "[@name=\"" + tControl.getName() + "\"]";
+ }
+
+ public CriteriaOrError getCriteria(TIED tied, TCBType cbType, String cbName) {
+ Optional compasSystemVersion = PrivateUtils.extractCompasPrivate(tied, TCompasSystemVersion.class);
+ if (compasSystemVersion.isEmpty()) {
+ return new CriteriaOrError(null, "No private COMPAS-SystemVersion found in this IED");
+ }
+ if (StringUtils.isBlank(compasSystemVersion.get().getMainSystemVersion())
+ || (StringUtils.isBlank(compasSystemVersion.get().getMinorSystemVersion()))) {
+ return new CriteriaOrError(null, "Missing MainSystemVersion or MinorSystemVersion attribute in COMPAS-SystemVersion private of IED");
+ }
+ String systemVersionWithoutV = removeVFromSystemVersion(compasSystemVersion.get());
+ Optional compasICDHeader = PrivateUtils.extractCompasPrivate(tied, TCompasICDHeader.class);
+ if (compasICDHeader.isEmpty()) {
+ return new CriteriaOrError(null, "No private COMPAS-ICDHeader found in this IED");
+ }
+ if (compasICDHeader.get().getIEDSystemVersioninstance() == null) {
+ return new CriteriaOrError(null, "No IEDSystemVersioninstance in the COMPAS-ICDHeader of this IED");
+ }
+ TBayIntOrExt bayIntOrExt = cbName.endsWith("I") ? TBayIntOrExt.BAY_INTERNAL : TBayIntOrExt.BAY_EXTERNAL;
+
+ return new CriteriaOrError(
+ new Criteria(cbType,
+ systemVersionWithoutV,
+ TIEDType.fromValue(compasICDHeader.get().getIEDType().value()),
+ TIEDRedundancy.fromValue(compasICDHeader.get().getIEDredundancy().value()),
+ compasICDHeader.get().getIEDSystemVersioninstance(),
+ bayIntOrExt), null);
+ }
+
+ private String removeVFromSystemVersion(TCompasSystemVersion compasSystemVersion) {
+ String[] minorVersionParts = compasSystemVersion.getMinorSystemVersion().split("\\.");
+ return (minorVersionParts.length == 3) ?
+ compasSystemVersion.getMainSystemVersion() + "." + minorVersionParts[0] + "." + minorVersionParts[1]
+ : null;
+ }
+
+ private Criteria vlanToCriteria(TVlan vlan) {
+ requireNotNull(vlan.getCBType(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "CBType");
+ requireNotBlank(vlan.getXY(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "XY");
+ requireNotBlank(vlan.getZW(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "ZW");
+ requireNotNull(vlan.getIEDType(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "IEDType");
+ requireNotNull(vlan.getIEDRedundancy(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "IEDRedundancy");
+ requireNotBlank(vlan.getIEDSystemVersionInstance(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "IEDSystemVersionInstance");
+ requireNotNull(vlan.getBayIntOrExt(), MISSING_ATTRIBUTE_IN_GSE_SMV_CB_COM + "BayIntOrExt");
+
+ return new Criteria(
+ vlan.getCBType(),
+ vlan.getXY() + "." + vlan.getZW(),
+ vlan.getIEDType(),
+ vlan.getIEDRedundancy(),
+ toIedSystemVersionInstance(vlan.getIEDSystemVersionInstance()),
+ vlan.getBayIntOrExt()
+ );
+ }
+
+ private Settings vlanToSetting(TVlan vlan) {
+ return new Settings(toVLanId(vlan.getVlanId()), toVlanPriority(vlan.getVlanPriority()), toDurationInMilliSec(vlan.getMinTime()), toDurationInMilliSec(vlan.getMaxTime()));
+ }
+
+ private void requireNotBlank(String str, String message) {
+ if (StringUtils.isBlank(str)) {
+ throw new ScdException(message);
+ }
+ }
+
+ private void requireNotNull(Object o, String message) {
+ if (Objects.isNull(o)) {
+ throw new ScdException(message);
+ }
+ }
+
+ private BigInteger toIedSystemVersionInstance(String strIedSystemVersionInstance) {
+ if (StringUtils.isBlank(strIedSystemVersionInstance)) {
+ return null;
+ }
+ BigInteger iedSystemVersionInstance;
+ try {
+ iedSystemVersionInstance = new BigInteger(strIedSystemVersionInstance);
+ } catch (NumberFormatException e) {
+ throw new ScdException("Error in Control Block communication setting file: IED System Version Instance must be an integer, but got : %s".formatted(strIedSystemVersionInstance));
+ }
+ return iedSystemVersionInstance;
+ }
+
+ private Integer toVLanId(String strVlanId) {
+ if (StringUtils.isBlank(strVlanId) || NONE.equalsIgnoreCase(strVlanId)) {
+ return null;
+ }
+ int vlanId;
+ try {
+ vlanId = Integer.parseInt(strVlanId);
+ } catch (NumberFormatException e) {
+ throw new ScdException("Error in Control Block communication setting file: VLAN ID must be an integer or '%s', but got : %s".formatted(NONE, strVlanId));
+ }
+ if (vlanId < 0 || vlanId > MAX_VLAN_ID) {
+ throw new ScdException("Error in Control Block communication setting file: VLAN ID must be between 0 and %d, but got : %s".formatted(MAX_VLAN_ID, strVlanId));
+ }
+ return vlanId;
+ }
+
+ private static Byte toVlanPriority(String strVlanPriority) {
+ if (StringUtils.isBlank(strVlanPriority) || NONE.equalsIgnoreCase(strVlanPriority)) {
+ return null;
+ }
+ byte vlanPriority;
+ try {
+ vlanPriority = Byte.parseByte(strVlanPriority);
+ } catch (NumberFormatException e) {
+ throw new ScdException("Error in Control Block communication setting file: VLAN Priority must be an integer or '%s', but got : %s".formatted(NONE, strVlanPriority));
+ }
+ if (vlanPriority < 0 || vlanPriority > MAX_VLAN_PRIORITY) {
+ throw new ScdException("Error in Control Block communication setting file: VLAN PRIORITY must be between 0 and %d, but got : %s".formatted(MAX_VLAN_PRIORITY, strVlanPriority));
+ }
+ return vlanPriority;
+ }
+
+ private TDurationInMilliSec toDurationInMilliSec(String strDuration) {
+ if (StringUtils.isBlank(strDuration) || NONE.equalsIgnoreCase(strDuration)) {
+ return null;
+ }
+ long duration;
+ try {
+ duration = Long.parseLong(strDuration);
+ } catch (NumberFormatException e) {
+ throw new ScdException("Error in Control Block communication setting file: VLAN MinTime and MaxTime must be an integer or '%s', but got : %s".formatted(NONE, strDuration));
+ }
+ return SclConstructorHelper.newDurationInMilliSec(duration);
+ }
+
+ /**
+ * Key to search for a control block communication setting
+ */
+ public record Criteria(TCBType cbType, String systemVersionWithoutV, TIEDType iedType, TIEDRedundancy iedRedundancy, BigInteger iedSystemVersionInstance, TBayIntOrExt bayIntOrExt) {
+ }
+
+ /**
+ * Communication settings for ControlBlock or Error message
+ */
+ public record CriteriaOrError(Criteria criteria, String errorMessage) {
+ }
+
+ /**
+ * Communication settings for ControlBlock
+ */
+ public record Settings(Integer vlanId, Byte vlanPriority, TDurationInMilliSec minTime, TDurationInMilliSec maxTime) {
+ }
+
+ /**
+ * All settings of CbCom in a useful format
+ */
+ record CbComSettings(PrimitiveIterator.OfLong appIdIterator, Iterator macAddressIterator, Map settingsByCriteria) {
+ }
+
+ record IedApLd(TIED ied, String apName, TLDevice lDevice) {
+ String getXPath() {
+ return """
+ /SCL/IED[@name="%s"]/AccessPoint[@name="%s"]/Server/LDevice[@inst="%s"]""".formatted(ied.getName(), apName, lDevice.getInst());
+ }
+
+ }
+}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockService.java
deleted file mode 100644
index 5f28d9e61..000000000
--- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ControlBlockService.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// SPDX-FileCopyrightText: 2022 2023 RTE FRANCE
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package org.lfenergy.compas.sct.commons;
-
-import org.apache.commons.lang3.StringUtils;
-import org.lfenergy.compas.scl2007b4.model.SCL;
-import org.lfenergy.compas.sct.commons.api.ControlBlockEditor;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.NetworkRanges;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.RangesPerCbType;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.Settings;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.SettingsOrError;
-import org.lfenergy.compas.sct.commons.dto.FcdaForDataSetsCreation;
-import org.lfenergy.compas.sct.commons.dto.SclReportItem;
-import org.lfenergy.compas.sct.commons.exception.ScdException;
-import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
-import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
-import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
-import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
-import org.lfenergy.compas.sct.commons.scl.ln.LNAdapter;
-import org.lfenergy.compas.sct.commons.util.ControlBlockEnum;
-import org.lfenergy.compas.sct.commons.util.Utils;
-
-import java.util.*;
-import java.util.stream.Stream;
-
-public class ControlBlockService implements ControlBlockEditor {
-
-
- @Override
- public List analyzeDataGroups(SCL scd) {
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- return sclRootAdapter.streamIEDAdapters()
- .map(iedAdapter -> {
- List list = new ArrayList<>();
- list.addAll(iedAdapter.checkDataGroupCoherence());
- list.addAll(iedAdapter.checkBindingDataGroupCoherence());
- return list;
- }).flatMap(Collection::stream).toList();
- }
-
- @Override
- public List createDataSetAndControlBlocks(SCL scd, Set allowedFcdas) {
- checkFcdaInitDataPresence(allowedFcdas);
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- Stream lDeviceAdapters = sclRootAdapter.streamIEDAdapters().flatMap(IEDAdapter::streamLDeviceAdapters);
- return createDataSetAndControlBlocks(lDeviceAdapters, allowedFcdas);
- }
-
- @Override
- public List createDataSetAndControlBlocks(SCL scd, String targetIedName, Set allowedFcdas) {
- checkFcdaInitDataPresence(allowedFcdas);
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
- return createDataSetAndControlBlocks(iedAdapter.streamLDeviceAdapters(), allowedFcdas);
-
- }
-
- @Override
- public List createDataSetAndControlBlocks(SCL scd, String targetIedName, String targetLDeviceInst, Set allowedFcdas) {
- if (StringUtils.isBlank(targetIedName)) {
- throw new ScdException("IED.name parameter is missing");
- }
- checkFcdaInitDataPresence(allowedFcdas);
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
- LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(targetLDeviceInst);
- return createDataSetAndControlBlocks(Stream.of(lDeviceAdapter), allowedFcdas);
- }
-
- private void checkFcdaInitDataPresence(Set allowedFcdas) {
- if (allowedFcdas == null || allowedFcdas.isEmpty()) {
- throw new ScdException("Accepted FCDAs list is empty, you should initialize allowed FCDA lists with CsvHelper class before");
- }
- }
-
- private List createDataSetAndControlBlocks(Stream lDeviceAdapters, Set allowedFcdas) {
- return lDeviceAdapters
- .map(lDeviceAdapter -> lDeviceAdapter.createDataSetAndControlBlocks(allowedFcdas))
- .flatMap(List::stream)
- .toList();
- }
-
- @Override
- public List configureNetworkForAllControlBlocks(SCL scd, ControlBlockNetworkSettings controlBlockNetworkSettings,
- RangesPerCbType rangesPerCbType) {
- List sclReportItems = new ArrayList<>();
- sclReportItems.addAll(configureNetworkForControlBlocks(scd, controlBlockNetworkSettings, rangesPerCbType.gse(), ControlBlockEnum.GSE));
- sclReportItems.addAll(configureNetworkForControlBlocks(scd, controlBlockNetworkSettings, rangesPerCbType.sampledValue(), ControlBlockEnum.SAMPLED_VALUE));
- return sclReportItems;
- }
-
- @Override
- public void removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(final SCL scl) {
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scl);
- List lDeviceAdapters = sclRootAdapter.streamIEDAdapters()
- .flatMap(IEDAdapter::streamLDeviceAdapters).toList();
- // LN0
- lDeviceAdapters.stream()
- .map(LDeviceAdapter::getLN0Adapter)
- .forEach(ln0 -> {
- ln0.removeAllControlBlocksAndDatasets();
- ln0.removeAllExtRefSourceBindings();
- });
- // Other LN
- lDeviceAdapters.stream()
- .map(LDeviceAdapter::getLNAdapters).flatMap(List::stream)
- .forEach(LNAdapter::removeAllControlBlocksAndDatasets);
- }
-
-
- private List configureNetworkForControlBlocks(SCL scd, ControlBlockNetworkSettings controlBlockNetworkSettings,
- NetworkRanges networkRanges, ControlBlockEnum controlBlockEnum) {
- PrimitiveIterator.OfLong appIdIterator = Utils.sequence(networkRanges.appIdStart(), networkRanges.appIdEnd());
- Iterator macAddressIterator = Utils.macAddressSequence(networkRanges.macAddressStart(), networkRanges.macAddressEnd());
-
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- return sclRootAdapter.streamIEDAdapters()
- .flatMap(iedAdapter ->
- iedAdapter.streamLDeviceAdapters()
- .filter(LDeviceAdapter::hasLN0)
- .map(LDeviceAdapter::getLN0Adapter)
- .flatMap(ln0Adapter -> ln0Adapter.streamControlBlocks(controlBlockEnum))
- .map(controlBlockAdapter -> configureControlBlockNetwork(controlBlockNetworkSettings, appIdIterator, macAddressIterator, controlBlockAdapter)))
- .flatMap(Optional::stream)
- .toList();
- }
-
- private Optional configureControlBlockNetwork(ControlBlockNetworkSettings controlBlockNetworkSettings, PrimitiveIterator.OfLong appIdIterator, Iterator macAddressIterator, ControlBlockAdapter controlBlockAdapter) {
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
- if (settingsOrError.errorMessage() != null) {
- return Optional.of(controlBlockAdapter.buildFatalReportItem(
- "Cannot configure network for this ControlBlock because: " + settingsOrError.errorMessage()));
- }
- Settings settings = settingsOrError.settings();
- if (settings == null) {
- return Optional.of(controlBlockAdapter.buildFatalReportItem(
- "Cannot configure network for this ControlBlock because no settings was provided"));
- }
- if (settings.vlanId() == null) {
- return Optional.of(controlBlockAdapter.buildFatalReportItem(
- "Cannot configure network for this ControlBlock because no Vlan Id was provided in the settings"));
- }
- if (!appIdIterator.hasNext()) {
- return Optional.of(controlBlockAdapter.buildFatalReportItem(
- "Cannot configure network for this ControlBlock because range of appId is exhausted"));
- }
- if (!macAddressIterator.hasNext()) {
- return Optional.of(controlBlockAdapter.buildFatalReportItem(
- "Cannot configure network for this ControlBlock because range of MAC Address is exhausted"));
- }
-
- return controlBlockAdapter.configureNetwork(appIdIterator.nextLong(), macAddressIterator.next(), settings.vlanId(), settings.vlanPriority(),
- settings.minTime(), settings.maxTime());
- }
-
-}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/ControlBlockEditor.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/ControlBlockEditor.java
index 7406c23c3..8235dd5ea 100644
--- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/ControlBlockEditor.java
+++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/ControlBlockEditor.java
@@ -6,9 +6,9 @@
import org.lfenergy.compas.scl2007b4.model.SCL;
import org.lfenergy.compas.scl2007b4.model.TExtRef;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
import org.lfenergy.compas.sct.commons.dto.FcdaForDataSetsCreation;
import org.lfenergy.compas.sct.commons.dto.SclReportItem;
+import org.lfenergy.compas.sct.commons.model.cbcom.CBCom;
import org.lfenergy.compas.sct.commons.util.Utils;
import java.util.List;
@@ -22,7 +22,7 @@
*
*
{@link ControlBlockEditor#createDataSetAndControlBlocks(SCL, Set) Create DataSet and ControlBlock based on the TExtRef}
*
{@link ControlBlockEditor#createDataSetAndControlBlocks(SCL, String, Set) Create DataSet and ControlBlock based on the TExtRef in given IED}
- *
{@link ControlBlockEditor#createDataSetAndControlBlocks(SCL, String,String, Set) Create DataSet and ControlBlock based on the TExtRef in given IED and LDevice}
+ *
{@link ControlBlockEditor#createDataSetAndControlBlocks(SCL, String, String, Set) Create DataSet and ControlBlock based on the TExtRef in given IED and LDevice}
*
{@link ControlBlockEditor#configureNetworkForAllControlBlocks Configure the network for the ControlBlocks}
*
{@link ControlBlockEditor#removeAllControlBlocksAndDatasetsAndExtRefSrcBindings Removes all ControlBlocks and DataSets for all LNs in SCL}
*
{@link ControlBlockEditor#analyzeDataGroups(SCL)} Checks Control Blocks, DataSets and FCDA number limitation into Access Points }
@@ -85,17 +85,11 @@ public interface ControlBlockEditor {
* - the Communication/SubNetwork/ConnectedAP/GSE element, for the GSEControl blocks
* - the Communication/SubNetwork/ConnectedAP/SMV element, for the SampledValueControl blocks
*
- * @param scd input SCD object. The object will be modified with the new DataGSESet and SMV elements
- * @param controlBlockNetworkSettings a method tha gives the network configuration information for a given ControlBlock
- * @param rangesPerCbType provide NetworkRanges for GSEControl and SampledValueControl. NetworkRanges contains :
- * start-end app APPID range (long value), start-end MAC-Addresses (Mac-Addresses values: Ex: "01-0C-CD-01-01-FF")
+ * @param scd input SCD object. The object will be modified with the new GSE and SMV elements
+ * @param cbCom communication settings to configure Control Block Communication
* @return list of encountered errors
* @see Utils#macAddressToLong(String) for the expected MAC address format
- * @see ControlBlockNetworkSettings
- * @see ControlBlockNetworkSettings.RangesPerCbType
- * @see ControlBlockNetworkSettings.NetworkRanges
*/
- List configureNetworkForAllControlBlocks(SCL scd, ControlBlockNetworkSettings controlBlockNetworkSettings,
- ControlBlockNetworkSettings.RangesPerCbType rangesPerCbType);
+ List configureNetworkForAllControlBlocks(SCL scd, CBCom cbCom);
}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettings.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettings.java
deleted file mode 100644
index 65fcb11f3..000000000
--- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettings.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// SPDX-FileCopyrightText: 2023 RTE FRANCE
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package org.lfenergy.compas.sct.commons.dto;
-
-import org.lfenergy.compas.scl2007b4.model.TDurationInMilliSec;
-import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
-
-/**
- * This interface has a single method which provides network settings for a ControlBlock.
- * These are used to create:
- * - the Communication/SubNetwork/ConnectedAP/GSE element, which is the network configuration of a GSEControl block
- * - the Communication/SubNetwork/ConnectedAP/SMV element, which is the network configuration of a SampledValueControl block
- * It is a FunctionalInterface, so it can be implemented with a lambda expression.
- *
- * @see org.lfenergy.compas.sct.commons.util.ControlBlockNetworkSettingsCsvHelper
- */
-@FunctionalInterface
-public interface ControlBlockNetworkSettings {
-
- /**
- * This method provides a vlanId, vlanPriority, minTime, maxTime for this ControlBlock.
- * vlanPriority will be ignored when vlanId is null.
- *
- * @param controlBlockAdapter ControlBlock for which we want to configure the communication section
- * @return network settings to use for configuring Communication section for this ControlBlock.
- * An error message can be provided (i.e. errorMessage not null) or a null settings, in order to avoid configuring the ControlBlock.
- */
- SettingsOrError getNetworkSettings(ControlBlockAdapter controlBlockAdapter);
-
- /**
- * Network settings for ControlBlock communication
- *
- * @param vlanId id of the vlan
- * @param vlanPriority priority for the vlan
- * @param minTime minTime for GSE communication element
- * @param maxTime maxTime for GSE communication element
- */
- record Settings(Integer vlanId, Byte vlanPriority, TDurationInMilliSec minTime, TDurationInMilliSec maxTime) {
- }
-
- /**
- * Network settings for ControlBlock communication or Error message
- *
- * @param settings Network settings for ControlBlock communication. Can be null when errorMessage is provided
- * @param errorMessage should be null if settings is provided
- */
- record SettingsOrError(Settings settings, String errorMessage) {
- }
-
- /**
- * NetworkRanges for GSEControl and SampledValueControl
- *
- * @param gse NetworkRanges for GSEControl
- * @param sampledValue NetworkRanges for SampledValueControl
- */
- record RangesPerCbType(NetworkRanges gse, NetworkRanges sampledValue) {
- }
-
- /**
- * Range of APPID and range of MAC-Address
- *
- * @param appIdStart range start for APPID (inclusive)
- * @param appIdEnd range end for APPID (inclusive)
- * @param macAddressStart range start for MAC-Addresses (inclusive). Ex: "01-0C-CD-01-00-00"
- * @param macAddressEnd range end for MAC-Addresses (inclusive). Ex: "01-0C-CD-01-01-FF"
- */
- record NetworkRanges(long appIdStart, long appIdEnd, String macAddressStart, String macAddressEnd) {
- }
-}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ControlService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ControlService.java
new file mode 100644
index 000000000..c1904d913
--- /dev/null
+++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ControlService.java
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: 2023 RTE FRANCE
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package org.lfenergy.compas.sct.commons.scl;
+
+import org.lfenergy.compas.scl2007b4.model.*;
+
+import java.util.stream.Stream;
+
+public class ControlService {
+
+ public Stream getControls(TAnyLN tAnyLN, Class tControlClass){
+ if (tControlClass == TGSEControl.class && tAnyLN instanceof TLN0 tln0 && tln0.isSetGSEControl()){
+ return tln0.getGSEControl().stream().map(tControlClass::cast);
+ } else if (tControlClass == TSampledValueControl.class && tAnyLN instanceof TLN0 tln0 && tln0.isSetSampledValueControl()){
+ return tln0.getSampledValueControl().stream().map(tControlClass::cast);
+ } else if (tControlClass == TReportControl.class && tAnyLN.isSetReportControl()){
+ return tAnyLN.getReportControl().stream().map(tControlClass::cast);
+ } else if (tControlClass == TLogControl.class){
+ return tAnyLN.getLogControl().stream().map(tControlClass::cast);
+ }
+ return Stream.empty();
+ }
+
+}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java
index 6902f2f5e..f6c539def 100644
--- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java
+++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapter.java
@@ -7,21 +7,10 @@
import org.lfenergy.compas.scl2007b4.model.*;
import org.lfenergy.compas.sct.commons.dto.ControlBlockTarget;
-import org.lfenergy.compas.sct.commons.dto.SclReportItem;
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
-import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
-import org.lfenergy.compas.sct.commons.scl.com.ConnectedAPAdapter;
-import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
import org.lfenergy.compas.sct.commons.scl.ln.AbstractLNAdapter;
import org.lfenergy.compas.sct.commons.util.ControlBlockEnum;
-import org.lfenergy.compas.sct.commons.util.Utils;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newDurationInMilliSec;
-import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newP;
import static org.lfenergy.compas.sct.commons.util.Utils.xpathAttributeFilter;
/**
@@ -52,12 +41,6 @@
public class ControlBlockAdapter extends SclElementAdapter, TControl> {
private static final long RPT_ENABLED_MAX_DEFAULT = 1L;
- private static final String APPID_P_TYPE = "APPID";
- private static final String MAC_ADDRESS_P_TYPE = "MAC-Address";
- private static final String VLAN_ID_P_TYPE = "VLAN-ID";
- private static final String VLAN_PRIORITY_P_TYPE = "VLAN-PRIORITY";
- private static final int APPID_LENGTH = 4;
- private static final int VLAN_ID_LENGTH = 3;
public ControlBlockAdapter(AbstractLNAdapter extends TAnyLN> parentAdapter, TControl tControl) {
super(parentAdapter, tControl);
@@ -128,67 +111,4 @@ public void addTargetIfNotExists(AbstractLNAdapter> targetLn) {
}
}
- /**
- * Configure the Communication section for this ControlBlock
- * - Communication/SubNetwork/ConnectedAP/GSE for GSEControl block
- * - Communication/SubNetwork/ConnectedAP/SMV for SampledValueControl block
- * @param appId value for P type APPID
- * @param macAddress value for P type MAC-Address
- * @param vlanId value for P type VLAN-ID
- * @param vlanPriority value for P type VLAN-PRIORITY
- * @param minTime MinTime Element
- * @param maxTime MaxTime Element
- * @return An empty Optional if network have been configured, else a SclReportItem.
- */
- public Optional configureNetwork(long appId, String macAddress, Integer vlanId, Byte vlanPriority, TDurationInMilliSec minTime,
- TDurationInMilliSec maxTime) {
- String accessPointName = getParentLDeviceAdapter().getAccessPoint().getName();
-
- Optional optConApAdapter = getSclRootAdapter().findConnectedApAdapter(getParentIedAdapter().getName(), accessPointName);
- if (optConApAdapter.isEmpty()) {
- return Optional.of(buildFatalReportItem("Cannot configure network for ControlBlock because no ConnectAP found for parent AccessPoint"));
- }
- ConnectedAPAdapter connectedAPAdapter = optConApAdapter.get();
- List listOfPs = new ArrayList<>();
- listOfPs.add(newP(APPID_P_TYPE, Utils.toHex(appId, APPID_LENGTH)));
- listOfPs.add(newP(MAC_ADDRESS_P_TYPE, macAddress));
- if (vlanId != null) {
- listOfPs.add(newP(VLAN_ID_P_TYPE, Utils.toHex(vlanId, VLAN_ID_LENGTH)));
- if (vlanPriority != null) {
- listOfPs.add(newP(VLAN_PRIORITY_P_TYPE, String.valueOf(vlanPriority)));
- }
- }
- switch (getControlBlockEnum()) {
- case GSE -> connectedAPAdapter.updateGseOrCreateIfNotExists(getParentLDeviceAdapter().getInst(), currentElem.getName(), listOfPs, newDurationInMilliSec(minTime), newDurationInMilliSec(maxTime));
- case SAMPLED_VALUE -> connectedAPAdapter.updateSmvOrCreateIfNotExists(getParentLDeviceAdapter().getInst(), currentElem.getName(), listOfPs);
- default -> {
- return Optional.of(buildFatalReportItem("configureNetwork not yet implemented for %s ControlBlocks".formatted(getControlBlockEnum())));
- }
- }
- return Optional.empty();
- }
-
- /**
- * Get parent LDevice
- * @return ControlBlock's parent lDeviceAdapter
- */
- private LDeviceAdapter getParentLDeviceAdapter() {
- return getParentAdapter().getParentAdapter();
- }
-
- /**
- * Get parent IED
- * @return ControlBlock's parent IEDAdapter
- */
- public IEDAdapter getParentIedAdapter() {
- return getParentAdapter().getParentIed();
- }
-
- /**
- * Get SCL Root
- * @return sclRootAdapter
- */
- private SclRootAdapter getSclRootAdapter() {
- return getParentIedAdapter().getParentAdapter();
- }
}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnum.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnum.java
index 23cb0bbcb..025b14992 100644
--- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnum.java
+++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnum.java
@@ -5,23 +5,23 @@
package org.lfenergy.compas.sct.commons.util;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import org.lfenergy.compas.scl2007b4.model.*;
+import org.lfenergy.compas.sct.commons.model.cbcom.TCBType;
import java.util.Arrays;
import java.util.Objects;
@Getter
+@RequiredArgsConstructor
public enum ControlBlockEnum {
- GSE(TGSEControl.class),
- SAMPLED_VALUE(TSampledValueControl.class),
- REPORT(TReportControl.class),
- LOG(TLogControl.class);
+ GSE(TGSEControl.class, "GSEControl"),
+ SAMPLED_VALUE(TSampledValueControl.class, "SampledValueControl"),
+ REPORT(TReportControl.class, "ReportControl"),
+ LOG(TLogControl.class, "LogControl");
private final Class extends TControl> controlBlockClass;
-
- ControlBlockEnum(Class extends TControl> controlBlockClass) {
- this.controlBlockClass = controlBlockClass;
- }
+ private final String elementName;
public static ControlBlockEnum from(TServiceType tServiceType) {
Objects.requireNonNull(tServiceType);
@@ -40,4 +40,12 @@ public static ControlBlockEnum from(Class extends TControl> tControlClass) {
.orElseThrow(() -> new IllegalArgumentException("Unsupported TControl class : " + tControlClass.getSimpleName()));
}
+ public static ControlBlockEnum from(TCBType tcbType) {
+ return switch (tcbType){
+ case GOOSE -> GSE;
+ case SV -> SAMPLED_VALUE;
+ default -> throw new IllegalArgumentException("Unsupported TCBType: " + tcbType);
+ };
+ }
+
}
diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockNetworkSettingsCsvHelper.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockNetworkSettingsCsvHelper.java
deleted file mode 100644
index dc4b2ff6a..000000000
--- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/ControlBlockNetworkSettingsCsvHelper.java
+++ /dev/null
@@ -1,204 +0,0 @@
-// SPDX-FileCopyrightText: 2023 RTE FRANCE
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package org.lfenergy.compas.sct.commons.util;
-
-import com.opencsv.bean.CsvBindByPosition;
-import lombok.ToString;
-import org.apache.commons.lang3.StringUtils;
-import org.lfenergy.compas.scl2007b4.model.*;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
-import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
-import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
-
-import java.io.Reader;
-import java.math.BigInteger;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * This class is an implementation example for interface ControlBlockNetworkSettings.
- * It relies on a CSV file.
- * The first columns of the CSV file are the criteria to match the ControlBlock (controlBlockEnum, systemVersionWithoutV, iedType, iedRedundancy,
- * isBayInternal),
- * The last columns are the network settings for the matched ControlBlock (as described in {@link ControlBlockNetworkSettings.Settings}).
- *
- * @see CsvUtils
- */
-public class ControlBlockNetworkSettingsCsvHelper implements ControlBlockNetworkSettings {
-
- private static final int MAX_VLAN_ID = 0x0FFF;
- private static final int MAX_VLAN_PRIORITY = 7;
- private static final String NONE = "none";
-
- private final Map allSettings;
-
- /**
- * Constructor
- * Provide the CSV file as a Reader. For example, you can create a reader like this :
- * new InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName), StandardCharsets.UTF_8);
- *
- * @param csvSource a reader that provides the data as CSV. For example :
- */
- public ControlBlockNetworkSettingsCsvHelper(Reader csvSource) {
- allSettings = readCsvFile(csvSource);
- }
-
- private Map readCsvFile(Reader csvSource) {
- return CsvUtils.parseRows(csvSource, Row.class).stream()
- .distinct()
- .collect(Collectors.toMap(
- ControlBlockNetworkSettingsCsvHelper::rowToCriteria,
- ControlBlockNetworkSettingsCsvHelper::rowToSetting
- ));
- }
-
- @Override
- public SettingsOrError getNetworkSettings(ControlBlockAdapter controlBlockAdapter) {
- ControlBlockEnum controlBlockEnum = controlBlockAdapter.getControlBlockEnum();
- IEDAdapter iedAdapter = controlBlockAdapter.getParentIedAdapter();
- Optional compasSystemVersion = iedAdapter.getCompasSystemVersion();
- if (compasSystemVersion.isEmpty()) {
- return new SettingsOrError(null, "No private COMPAS-SystemVersion found in this IED");
- }
- String systemVersionWithoutV = removeVFromSystemVersion(compasSystemVersion.get());
- Optional compasICDHeader = iedAdapter.getCompasICDHeader();
- if (compasICDHeader.isEmpty()) {
- return new SettingsOrError(null, "No private COMPAS-ICDHeader found in this IED");
- }
- TCompasIEDType iedType = compasICDHeader.get().getIEDType();
- TCompasIEDRedundancy iedRedundancy = compasICDHeader.get().getIEDredundancy();
- BigInteger iedSystemVersionInstance = compasICDHeader.get().getIEDSystemVersioninstance();
- boolean isBayInternal = controlBlockAdapter.getName().endsWith("I");
-
- Criteria criteria = new Criteria(controlBlockEnum, systemVersionWithoutV, iedType, iedRedundancy, iedSystemVersionInstance, isBayInternal);
- Settings settings = findSettings(criteria);
- return settings != null ?
- new SettingsOrError(settings, null) :
- new SettingsOrError(null, "No row found with these criteria " + criteria);
- }
-
- private Settings findSettings(Criteria criteria) {
- Objects.requireNonNull(criteria);
- if (criteria.systemVersionWithoutV() == null
- || criteria.iedType() == null
- || criteria.iedRedundancy() == null
- || criteria.iedSystemVersionInstance == null) {
- return null;
- }
- return allSettings.get(criteria);
- }
-
- private static String removeVFromSystemVersion(TCompasSystemVersion compasSystemVersion) {
- if (StringUtils.isBlank(compasSystemVersion.getMainSystemVersion())
- || (StringUtils.isBlank(compasSystemVersion.getMinorSystemVersion()))) {
- return null;
- }
- String[] minorVersionParts = compasSystemVersion.getMinorSystemVersion().split("\\.");
- return (minorVersionParts.length == 3) ?
- compasSystemVersion.getMainSystemVersion() + "." + minorVersionParts[0] + "." + minorVersionParts[1]
- : null;
- }
-
- private static Criteria rowToCriteria(Row row) {
- if (StringUtils.isBlank(row.cbType)
- || StringUtils.isBlank(row.xy)
- || StringUtils.isBlank(row.zw)
- || StringUtils.isBlank(row.iedType)
- || StringUtils.isBlank(row.iedRedundancy)
- || StringUtils.isBlank(row.iedSystemVersionInstance)
- || StringUtils.isBlank(row.bindingType)
- ) {
- throw new IllegalArgumentException("At least one criteria is null in row " + row);
- }
- ControlBlockEnum controlBlockEnum = switch (row.cbType) {
- case "GOOSE" -> ControlBlockEnum.GSE;
- case "SV" -> ControlBlockEnum.SAMPLED_VALUE;
- default -> throw new IllegalArgumentException("Unsupported Control Block Type : " + row.cbType);
- };
- return new Criteria(
- controlBlockEnum,
- row.xy + "." + row.zw,
- TCompasIEDType.fromValue(row.iedType),
- TCompasIEDRedundancy.fromValue(row.iedRedundancy),
- new BigInteger(row.iedSystemVersionInstance),
- row.bindingType.equals("BAY_INTERNAL")
- );
- }
-
- private static Settings rowToSetting(Row row) {
- Integer vlanId = toVLanId(row.vlanId);
- Byte vlanPriority = toVlanPriority(row.vlanPriority);
- TDurationInMilliSec minTime = toDurationInMilliSec(row.minTime);
- TDurationInMilliSec maxTime = toDurationInMilliSec(row.maxTime);
- return new Settings(vlanId, vlanPriority, minTime, maxTime);
- }
-
- private static Byte toVlanPriority(String strVlanPriority) {
- if (StringUtils.isBlank(strVlanPriority) || NONE.equalsIgnoreCase(strVlanPriority)) {
- return null;
- }
- byte vlanPriority = Byte.parseByte(strVlanPriority);
- if (vlanPriority < 0 || vlanPriority > MAX_VLAN_PRIORITY) {
- throw new IllegalArgumentException("VLAN PRIORITY must be between 0 and %d, but got : %d".formatted(MAX_VLAN_PRIORITY, vlanPriority));
- }
- return vlanPriority;
- }
-
- private static Integer toVLanId(String strVlanId) {
- if (StringUtils.isBlank(strVlanId) || NONE.equalsIgnoreCase(strVlanId)) {
- return null;
- }
- int vlanId = Integer.parseInt(strVlanId);
- if (vlanId < 0 || vlanId > MAX_VLAN_ID) {
- throw new IllegalArgumentException("VLAN ID must be between 0 and %d, but got : %d".formatted(MAX_VLAN_ID, vlanId));
- }
- return vlanId;
- }
-
- private static TDurationInMilliSec toDurationInMilliSec(String duration) {
- if (StringUtils.isBlank(duration) || NONE.equalsIgnoreCase(duration)) {
- return null;
- }
- return SclConstructorHelper.newDurationInMilliSec(Long.parseLong(duration));
- }
-
- private record Criteria(
- ControlBlockEnum controlBlockEnum,
- String systemVersionWithoutV,
- TCompasIEDType iedType,
- TCompasIEDRedundancy iedRedundancy,
- BigInteger iedSystemVersionInstance,
- boolean isBayInternal) {
- }
-
- @ToString
- public static class Row {
- @CsvBindByPosition(position = 0)
- private String cbType;
- @CsvBindByPosition(position = 1)
- private String xy;
- @CsvBindByPosition(position = 2)
- private String zw;
- @CsvBindByPosition(position = 3)
- private String iedType;
- @CsvBindByPosition(position = 4)
- private String iedRedundancy;
- @CsvBindByPosition(position = 5)
- private String iedSystemVersionInstance;
- @CsvBindByPosition(position = 6)
- private String bindingType;
- @CsvBindByPosition(position = 7)
- private String vlanId;
- @CsvBindByPosition(position = 8)
- private String vlanPriority;
- @CsvBindByPosition(position = 9)
- private String minTime;
- @CsvBindByPosition(position = 10)
- private String maxTime;
- }
-
-}
diff --git a/sct-commons/src/main/resources/xsd/GSE_SMV_CB_COM.xsd b/sct-commons/src/main/resources/xsd/GSE_SMV_CB_COM.xsd
new file mode 100644
index 000000000..dbc9bbe3c
--- /dev/null
+++ b/sct-commons/src/main/resources/xsd/GSE_SMV_CB_COM.xsd
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IED type to be used to identity the set of LDevice.inst handled by the IED
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sct-commons/src/main/resources/xsd/LDEPF_Config_file_v2.xsd b/sct-commons/src/main/resources/xsd/LDEPF.xsd
similarity index 100%
rename from sct-commons/src/main/resources/xsd/LDEPF_Config_file_v2.xsd
rename to sct-commons/src/main/resources/xsd/LDEPF.xsd
diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ControlBlockServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ControlBlockEditorServiceTest.java
similarity index 52%
rename from sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ControlBlockServiceTest.java
rename to sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ControlBlockEditorServiceTest.java
index 9045762fa..3a720f6de 100644
--- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ControlBlockServiceTest.java
+++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ControlBlockEditorServiceTest.java
@@ -7,16 +7,16 @@
import org.assertj.core.groups.Tuple;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.lfenergy.compas.scl2007b4.model.*;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
import org.lfenergy.compas.sct.commons.dto.ControlBlockTarget;
import org.lfenergy.compas.sct.commons.dto.FcdaForDataSetsCreation;
import org.lfenergy.compas.sct.commons.dto.SclReportItem;
import org.lfenergy.compas.sct.commons.exception.ScdException;
+import org.lfenergy.compas.sct.commons.model.cbcom.*;
+import org.lfenergy.compas.sct.commons.scl.ControlService;
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
import org.lfenergy.compas.sct.commons.scl.ied.DataSetAdapter;
@@ -29,45 +29,33 @@
import org.lfenergy.compas.sct.commons.testhelpers.MarshallerWrapper;
import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller;
import org.lfenergy.compas.sct.commons.util.CsvUtils;
-import org.mockito.InjectMocks;
-import org.mockito.junit.jupiter.MockitoExtension;
+import org.lfenergy.compas.sct.commons.util.PrivateEnum;
+import org.lfenergy.compas.sct.commons.util.PrivateUtils;
-import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.*;
import static org.lfenergy.compas.scl2007b4.model.TFCEnum.ST;
-import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.*;
import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*;
import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable;
import static org.lfenergy.compas.sct.commons.util.ControlBlockEnum.*;
-import static org.lfenergy.compas.sct.commons.util.SclConstructorHelper.newDurationInMilliSec;
-@ExtendWith(MockitoExtension.class)
-class ControlBlockServiceTest {
+class ControlBlockEditorServiceTest {
- @InjectMocks
- ControlBlockService controlBlockService;
+ ControlBlockEditorService controlBlockEditorService;
private Set allowedFcdas;
- private static final long GSE_APP_ID_MIN = 0x9;
- private static final long SMV_APP_ID_MIN = 0x400A;
- private static final String GSE_MAC_ADDRESS_PREFIX = "01-02-03-04-";
- private static final String SMV_MAC_ADDRESS_PREFIX = "0A-0B-0C-0D-";
- private static final NetworkRanges GSE_NETWORK_RANGES = new NetworkRanges(GSE_APP_ID_MIN, GSE_APP_ID_MIN + 10, GSE_MAC_ADDRESS_PREFIX + "00-FF", GSE_MAC_ADDRESS_PREFIX + "01-AA");
- private static final NetworkRanges SMV_NETWORK_RANGES = new NetworkRanges(SMV_APP_ID_MIN, SMV_APP_ID_MIN + 10, SMV_MAC_ADDRESS_PREFIX + "00-FF", SMV_MAC_ADDRESS_PREFIX + "01-AA");
- private static final RangesPerCbType RANGES_PER_CB_TYPE = new RangesPerCbType(GSE_NETWORK_RANGES, SMV_NETWORK_RANGES);
-
-
@BeforeEach
void init() {
+ controlBlockEditorService = new ControlBlockEditorService(new ControlService());
allowedFcdas = new HashSet<>(CsvUtils.parseRows("FcdaCandidates.csv", StandardCharsets.UTF_8, FcdaForDataSetsCreation.class));
}
@@ -82,7 +70,7 @@ void analyzeDataGroups_should_success() {
iedAdapter1.getCurrentElem().getAccessPoint().get(0).getServices().getClientServices().setMaxSMV(2L);
iedAdapter1.getCurrentElem().getAccessPoint().get(0).getServices().getClientServices().setMaxReports(1L);
// When
- List sclReportItems = controlBlockService.analyzeDataGroups(scd);
+ List sclReportItems = controlBlockEditorService.analyzeDataGroups(scd);
//Then
assertThat(sclReportItems).isEmpty();
@@ -100,7 +88,7 @@ void analyzeDataGroups_should_return_errors_messages() {
iedAdapter.getCurrentElem().getAccessPoint().get(0).getServices().getGOOSE().setMax(2L);
iedAdapter.getCurrentElem().getAccessPoint().get(0).getServices().getConfReportControl().setMax(0L);
// When
- List sclReportItems = controlBlockService.analyzeDataGroups(scd);
+ List sclReportItems = controlBlockEditorService.analyzeDataGroups(scd);
//Then
assertThat(sclReportItems).hasSize(11)
.extracting(SclReportItem::message)
@@ -118,13 +106,12 @@ void analyzeDataGroups_should_return_errors_messages() {
"There are too much SMV Control Blocks for the IED IED_NAME2: 3 > 1 max");
}
-
@Test
void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_srcXXX_attributes_on_ExtRef() {
// Given
SCL scl = SclTestMarshaller.getSCLFromFile("/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml");
// When
- controlBlockService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl);
+ controlBlockEditorService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl);
// Then
SclRootAdapter scdRootAdapter = new SclRootAdapter(scl);
List extRefs = scdRootAdapter
@@ -157,7 +144,7 @@ void createDataSetAndControlBlocks_should_Throw_Exception_when_list_allowed_fcda
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When Then
- assertThatCode(() -> controlBlockService.createDataSetAndControlBlocks(scd, fcdaForDataSets))
+ assertThatCode(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, fcdaForDataSets))
.isInstanceOf(ScdException.class)
.hasMessage("Accepted FCDAs list is empty, you should initialize allowed FCDA lists with CsvHelper class before");
}
@@ -167,7 +154,7 @@ void createDataSetAndControlBlocks_should_create_DataSet() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
assertThat(streamAllDataSets(scd)).hasSize(6);
@@ -198,7 +185,7 @@ void createDataSetAndControlBlocks_should_create_ControlBlocks() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
@@ -231,7 +218,7 @@ void createDataSetAndControlBlocks_should_set_ExtRef_srcXXX_attributes() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
@@ -261,7 +248,7 @@ void createDataSetAndControlBlocks_with_targetIedName_should_Throw_Exception_whe
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When Then
- assertThatCode(() -> controlBlockService.createDataSetAndControlBlocks(scd, "IED_NAME1", fcdaForDataSets))
+ assertThatCode(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, "IED_NAME1", fcdaForDataSets))
.isInstanceOf(ScdException.class)
.hasMessage("Accepted FCDAs list is empty, you should initialize allowed FCDA lists with CsvHelper class before");
}
@@ -271,7 +258,7 @@ void createDataSetAndControlBlocks_when_targetIedName_is_provided_should_succeed
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, "IED_NAME1", allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, "IED_NAME1", allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
assertThat(streamAllDataSets(scd)).hasSize(6);
@@ -287,7 +274,7 @@ void createDataSetAndControlBlocks_when_targetIedName_is_provided_and_no_ext_ref
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, "IED_NAME2", allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, "IED_NAME2", allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
assertThat(streamAllDataSets(scd)).isEmpty();
@@ -298,7 +285,7 @@ void createDataSetAndControlBlocks_when_targetIedName_is_not_found_should_throw_
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When & Then
- assertThatThrownBy(() -> controlBlockService.createDataSetAndControlBlocks(scd, "non_existing_IED_name", allowedFcdas))
+ assertThatThrownBy(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, "non_existing_IED_name", allowedFcdas))
.isInstanceOf(ScdException.class)
.hasMessage("IED.name 'non_existing_IED_name' not found in SCD");
}
@@ -309,7 +296,7 @@ void createDataSetAndControlBlocks_with_targetIedName_and_targetLDeviceInst_shou
// Given
SCL scd = new SCL();
// When Then
- assertThatCode(() -> controlBlockService.createDataSetAndControlBlocks(scd, "IED_NAME1", "LD_INST11", fcdaForDataSets))
+ assertThatCode(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, "IED_NAME1", "LD_INST11", fcdaForDataSets))
.isInstanceOf(ScdException.class)
.hasMessage("Accepted FCDAs list is empty, you should initialize allowed FCDA lists with CsvHelper class before");
}
@@ -319,7 +306,7 @@ void createDataSetAndControlBlocks_when_targetIedName_and_targetLDeviceInst_is_p
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, "IED_NAME1", "LD_INST11", allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, "IED_NAME1", "LD_INST11", allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
}
@@ -329,7 +316,7 @@ void createDataSetAndControlBlocks_when_targetIedName_is_not_found_and_targetLDe
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When & Then
- assertThatThrownBy(() -> controlBlockService.createDataSetAndControlBlocks(scd, "non_existing_IED_name", "LD_INST11", allowedFcdas))
+ assertThatThrownBy(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, "non_existing_IED_name", "LD_INST11", allowedFcdas))
.isInstanceOf(ScdException.class)
.hasMessage("IED.name 'non_existing_IED_name' not found in SCD");
}
@@ -339,7 +326,7 @@ void createDataSetAndControlBlocks_when_targetIedName_and_targetLDeviceInst_is_n
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When & Then
- assertThatThrownBy(() -> controlBlockService.createDataSetAndControlBlocks(scd, "IED_NAME1", "non_existing_LDevice_inst", allowedFcdas))
+ assertThatThrownBy(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, "IED_NAME1", "non_existing_LDevice_inst", allowedFcdas))
.isInstanceOf(ScdException.class)
.hasMessage("LDevice.inst 'non_existing_LDevice_inst' not found in IED 'IED_NAME1'");
}
@@ -349,19 +336,18 @@ void createDataSetAndControlBlocks_when_targetLDeviceInst_is_provided_without_ta
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
// When & Then
- assertThatThrownBy(() -> controlBlockService.createDataSetAndControlBlocks(scd, null, "LD_INST11", allowedFcdas))
+ assertThatThrownBy(() -> controlBlockEditorService.createDataSetAndControlBlocks(scd, null, "LD_INST11", allowedFcdas))
.isInstanceOf(ScdException.class)
.hasMessage("IED.name parameter is missing");
}
-
@Test
void updateAllSourceDataSetsAndControlBlocks_should_sort_FCDA_inside_DataSet_and_avoid_duplicates() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success_test_fcda_sort.xml");
// When
- List sclReportItems = controlBlockService.createDataSetAndControlBlocks(scd, allowedFcdas);
+ List sclReportItems = controlBlockEditorService.createDataSetAndControlBlocks(scd, allowedFcdas);
// Then
assertThat(sclReportItems).isEmpty();
DataSetAdapter dataSetAdapter = findDataSet(scd, "IED_NAME2", "LD_INST21", "DS_LD_INST21_GSI");
@@ -376,45 +362,73 @@ void updateAllSourceDataSetsAndControlBlocks_should_sort_FCDA_inside_DataSet_and
}
@Test
- void configureNetworkForAllControlBlocks_should_create_GSE_and_SMV_elements() {
+ void configureNetworkForAllControlBlocks_should_create_GSE_elements() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ CBCom cbCom = createCbCom();
+ // When
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
+ // Then
+ assertThat(sclReportItems.stream().noneMatch(SclReportItem::isError)).isTrue();
+ TGSE gse1 = getCommunicationGSE(scd, "IED_NAME2", "CB_LD_INST21_GSI");
+ assertThat(gse1.getLdInst()).isEqualTo("LD_INST21");
+ assertThat(SclDuration.from(gse1.getMinTime())).isEqualTo(new SclDuration("10", "s", "m"));
+ assertThat(SclDuration.from(gse1.getMaxTime())).isEqualTo(new SclDuration("2000", "s", "m"));
+ assertThat(gse1.getAddress().getP()).extracting(TP::getType, TP::getValue).containsExactlyInAnyOrder(
+ Tuple.tuple("VLAN-PRIORITY", "1"),
+ Tuple.tuple("APPID", "0000"),
+ Tuple.tuple("MAC-Address", "01-0C-CD-01-00-00"),
+ Tuple.tuple("VLAN-ID", "12D")
+ );
+ TGSE gse2 = getCommunicationGSE(scd, "IED_NAME2", "CB_LD_INST21_GMI");
+ assertThat(gse2.getLdInst()).isEqualTo("LD_INST21");
+ assertThat(SclDuration.from(gse2.getMinTime())).isEqualTo(new SclDuration("10", "s", "m"));
+ assertThat(SclDuration.from(gse2.getMaxTime())).isEqualTo(new SclDuration("2000", "s", "m"));
+ assertThat(gse2.getAddress().getP()).extracting(TP::getType, TP::getValue).containsExactlyInAnyOrder(
+ Tuple.tuple("VLAN-PRIORITY", "1"),
+ Tuple.tuple("APPID", "0001"),
+ Tuple.tuple("MAC-Address", "01-0C-CD-01-00-01"),
+ Tuple.tuple("VLAN-ID", "12D")
+ );
+ TGSE gse3 = getCommunicationGSE(scd, "IED_NAME3", "CB_LD_INST31_GSE");
+ assertThat(gse3.getLdInst()).isEqualTo("LD_INST31");
+ assertThat(SclDuration.from(gse3.getMinTime())).isEqualTo(new SclDuration("10", "s", "m"));
+ assertThat(SclDuration.from(gse3.getMaxTime())).isEqualTo(new SclDuration("2000", "s", "m"));
+ assertThat(gse3.getAddress().getP()).extracting(TP::getType, TP::getValue).containsExactlyInAnyOrder(
+ Tuple.tuple("VLAN-PRIORITY", "2"),
+ Tuple.tuple("APPID", "0002"),
+ Tuple.tuple("MAC-Address", "01-0C-CD-01-00-02"),
+ Tuple.tuple("VLAN-ID", "12E")
+ );
+ MarshallerWrapper.assertValidateXmlSchema(scd);
+ }
- TDurationInMilliSec minTime = newDurationInMilliSec(10);
- TDurationInMilliSec maxTime = newDurationInMilliSec(2000);
- ControlBlockNetworkSettings controlBlockNetworkSettings = controlBlockAdapter -> new SettingsOrError(new Settings(0x1D6, (byte) 4, minTime, maxTime), null);
-
+ @Test
+ void configureNetworkForAllControlBlocks_should_create_SMV_elements() {
+ // Given
+ SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ CBCom cbCom = createCbCom();
// When
- List sclReportItems = controlBlockService.configureNetworkForAllControlBlocks(scd, controlBlockNetworkSettings, RANGES_PER_CB_TYPE);
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
// Then
assertThat(sclReportItems.stream().noneMatch(SclReportItem::isError)).isTrue();
- TConnectedAP connectedAP = new SclRootAdapter(scd).findConnectedApAdapter("IED_NAME2", "AP_NAME").get().getCurrentElem();
- TGSE gse = connectedAP.getGSE().stream()
- .filter(tgse -> "CB_LD_INST21_GSI".equals(tgse.getCbName()))
- .findFirst().get();
- assertThat(gse.getLdInst()).isEqualTo("LD_INST21");
- assertThat(gse.getMinTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("10"));
- assertThat(gse.getMaxTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("2000"));
- assertThat(gse.getAddress().getP()).extracting(TP::getType, TP::getValue)
- .containsExactlyInAnyOrder(
- Tuple.tuple("VLAN-PRIORITY", "4"),
- Tuple.tuple("APPID", "0009"),
- Tuple.tuple("MAC-Address", "01-02-03-04-00-FF"),
- Tuple.tuple("VLAN-ID", "1D6")
- );
- TSMV smv = connectedAP.getSMV().stream()
- .filter(tsmv -> "CB_LD_INST21_SVI".equals(tsmv.getCbName()))
- .findFirst().get();
- assertThat(smv.getLdInst()).isEqualTo("LD_INST21");
- assertThat(smv.getAddress().getP()).extracting(TP::getType, TP::getValue)
- .containsExactlyInAnyOrder(
- Tuple.tuple("VLAN-PRIORITY", "4"),
- Tuple.tuple("APPID", "400A"),
- Tuple.tuple("MAC-Address", "0A-0B-0C-0D-00-FF"),
- Tuple.tuple("VLAN-ID", "1D6")
- );
+ TSMV smv1 = getCommunicationSMV(scd, "IED_NAME2", "CB_LD_INST21_SVI");
+ assertThat(smv1.getLdInst()).isEqualTo("LD_INST21");
+ assertThat(smv1.getAddress().getP()).extracting(TP::getType, TP::getValue).containsExactlyInAnyOrder(
+ Tuple.tuple("VLAN-PRIORITY", "3"),
+ Tuple.tuple("APPID", "4000"),
+ Tuple.tuple("MAC-Address", "01-0C-CD-04-00-00"),
+ Tuple.tuple("VLAN-ID", "12F")
+ );
+ assertThat(sclReportItems.stream().noneMatch(SclReportItem::isError)).isTrue();
+ TSMV smv2 = getCommunicationSMV(scd, "IED_NAME3", "CB_LD_INST31_SVE");
+ assertThat(smv2.getLdInst()).isEqualTo("LD_INST31");
+ assertThat(smv2.getAddress().getP()).extracting(TP::getType, TP::getValue).containsExactlyInAnyOrder(
+ Tuple.tuple("VLAN-PRIORITY", "4"),
+ Tuple.tuple("APPID", "4001"),
+ Tuple.tuple("MAC-Address", "01-0C-CD-04-00-01"),
+ Tuple.tuple("VLAN-ID", "130")
+ );
MarshallerWrapper.assertValidateXmlSchema(scd);
}
@@ -422,12 +436,13 @@ void configureNetworkForAllControlBlocks_should_create_GSE_and_SMV_elements() {
void configureNetworkForAllControlBlocks_should_create_GSE_with_incremental_appid_and_mac_addresses() {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
-
- TDurationInMilliSec minTime = newDurationInMilliSec(10);
- TDurationInMilliSec maxTime = newDurationInMilliSec(2000);
- ControlBlockNetworkSettings controlBlockNetworkSettings = controlBlockAdapter -> new SettingsOrError(new Settings(0x1D6, (byte) 4, minTime, maxTime), null);
+ CBCom cbCom = createCbCom();
+ cbCom.getAppIdRanges().getAppIdRange().get(0).setStart("0009");
+ cbCom.getAppIdRanges().getAppIdRange().get(0).setEnd("000B");
+ cbCom.getMacRanges().getMacRange().get(0).setStart("01-02-03-04-00-FF");
+ cbCom.getMacRanges().getMacRange().get(0).setEnd("01-02-03-04-01-01");
// When
- List sclReportItems = controlBlockService.configureNetworkForAllControlBlocks(scd, controlBlockNetworkSettings, RANGES_PER_CB_TYPE);
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
// Then
assertThat(sclReportItems.stream().noneMatch(SclReportItem::isError)).isTrue();
assertThat(streamAllConnectedApGseP(scd, "APPID"))
@@ -438,19 +453,160 @@ void configureNetworkForAllControlBlocks_should_create_GSE_with_incremental_appi
@ParameterizedTest
@MethodSource("provideConfigureNetworkForAllControlBlocksErrors")
- void configureNetworkForAllControlBlocks_should_fail_when_no_settings_for_this_controlBlock(ControlBlockNetworkSettings controlBlockNetworkSettings,
- RangesPerCbType rangesPerCbType,
- String expectedMessage) {
+ void configureNetworkForAllControlBlocks_should_fail_when_no_settings_for_this_controlBlock(CBCom cbCom, String expectedMessage, String expectedXPath) {
// Given
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
// When
- List sclReportItems = controlBlockService.configureNetworkForAllControlBlocks(scd, controlBlockNetworkSettings, rangesPerCbType);
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
// Then
assertThat(sclReportItems.stream().noneMatch(SclReportItem::isError)).isFalse();
assertThat(sclReportItems)
- .extracting(SclReportItem::message, SclReportItem::xpath)
- .contains(Tuple.tuple(expectedMessage,
- "/SCL/IED[@name=\"IED_NAME2\"]/AccessPoint/Server/LDevice[@inst=\"LD_INST21\"]/LN0/GSEControl[@name=\"CB_LD_INST21_GMI\"]"));
+ .contains(SclReportItem.error(expectedXPath, expectedMessage));
+ }
+
+ public static Stream provideConfigureNetworkForAllControlBlocksErrors() {
+ CBCom cbComWithNoVlan = createCbCom();
+ cbComWithNoVlan.getVlans().getVlan().clear();
+ CBCom cbComWithMissingVlanId = createCbCom();
+ cbComWithMissingVlanId.getVlans().getVlan().get(0).setVlanId(null);
+ CBCom cbComWithNotEnoughAppId = createCbCom();
+ cbComWithNotEnoughAppId.getAppIdRanges().getAppIdRange().get(0).setStart("0000");
+ cbComWithNotEnoughAppId.getAppIdRanges().getAppIdRange().get(0).setEnd("00001");
+ CBCom cbComWithNotEnoughMacAddress = createCbCom();
+ cbComWithNotEnoughMacAddress.getMacRanges().getMacRange().get(0).setStart("01-0C-CD-01-00-00");
+ cbComWithNotEnoughMacAddress.getMacRanges().getMacRange().get(0).setEnd("01-0C-CD-01-00-01");
+
+ return Stream.of(
+ Arguments.of(cbComWithNoVlan, "Cannot configure communication for this ControlBlock because: No controlBlock communication settings found with these Criteria[cbType=GOOSE, systemVersionWithoutV=01.00.009.001, iedType=BCU, iedRedundancy=A, iedSystemVersionInstance=1, bayIntOrExt=BAY_INTERNAL]",
+ "/SCL/IED[@name=\"IED_NAME2\"]/AccessPoint[@name=\"AP_NAME\"]/Server/LDevice[@inst=\"LD_INST21\"]/LN0/GSEControl[@name=\"CB_LD_INST21_GMI\"]"),
+ Arguments.of(cbComWithMissingVlanId, "Cannot configure communication for this ControlBlock because no Vlan Id was provided in the settings",
+ "/SCL/IED[@name=\"IED_NAME2\"]/AccessPoint[@name=\"AP_NAME\"]/Server/LDevice[@inst=\"LD_INST21\"]/LN0/GSEControl[@name=\"CB_LD_INST21_GMI\"]"),
+ Arguments.of(cbComWithNotEnoughAppId, "Cannot configure communication for this ControlBlock because range of appId is exhausted",
+ "/SCL/IED[@name=\"IED_NAME3\"]/AccessPoint[@name=\"AP_NAME\"]/Server/LDevice[@inst=\"LD_INST31\"]/LN0/GSEControl[@name=\"CB_LD_INST31_GSE\"]"),
+ Arguments.of(cbComWithNotEnoughMacAddress, "Cannot configure communication for this ControlBlock because range of MAC Address is exhausted",
+ "/SCL/IED[@name=\"IED_NAME3\"]/AccessPoint[@name=\"AP_NAME\"]/Server/LDevice[@inst=\"LD_INST31\"]/LN0/GSEControl[@name=\"CB_LD_INST31_GSE\"]")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBlankCriteria")
+ void configureNetworkForAllControlBlocks_when_setting_files_has_blank_criteria_should_return_error(Consumer setCriteriaBlank) {
+ // Given
+ SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ CBCom cbCom = createCbCom();
+ setCriteriaBlank.accept(cbCom.getVlans().getVlan().get(0));
+ //When
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
+ //Then
+ assertThat(sclReportItems).hasSize(1);
+ assertThat(sclReportItems.get(0)).extracting(SclReportItem::isError, SclReportItem::xpath)
+ .containsExactly(true, "Control Block Communication setting files");
+ assertThat(sclReportItems.get(0).message()).matches("Error in Control Block communication setting file: vlan is missing attribute .*");
+ }
+
+ private static Stream provideBlankCriteria() {
+ return Stream.of(Arguments.of(
+ (Consumer) tVlan -> tVlan.setXY(null),
+ (Consumer) tVlan -> tVlan.setZW(null),
+ (Consumer) tVlan -> tVlan.setIEDType(null),
+ (Consumer) tVlan -> tVlan.setIEDRedundancy(null),
+ (Consumer) tVlan -> tVlan.setIEDSystemVersionInstance(null),
+ (Consumer) tVlan -> tVlan.setBayIntOrExt(null)
+ ));
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideMalformedNumbers")
+ void configureNetworkForAllControlBlocks_when_malformed_numbers_should_return_error(Consumer setMalformedNumber) {
+ // Given
+ SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ CBCom cbCom = createCbCom();
+ setMalformedNumber.accept(cbCom.getVlans().getVlan().get(0));
+ //When
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
+ //Then
+ assertThat(sclReportItems).hasSize(1);
+ assertThat(sclReportItems.get(0)).extracting(SclReportItem::isError, SclReportItem::xpath)
+ .containsExactly(true, "Control Block Communication setting files");
+ assertThat(sclReportItems.get(0).message()).matches("Error in Control Block communication setting file: .+ must be an integer( or 'none')?, but got : XXX");
+ }
+
+ private static Stream provideMalformedNumbers() {
+ return Stream.of(
+ Arguments.of((Consumer) tVlan -> tVlan.setIEDSystemVersionInstance("XXX")),
+ Arguments.of((Consumer) tVlan -> tVlan.setVlanId("XXX")),
+ Arguments.of((Consumer) tVlan -> tVlan.setVlanPriority("XXX")),
+ Arguments.of((Consumer) tVlan -> tVlan.setMinTime("XXX")),
+ Arguments.of((Consumer) tVlan -> tVlan.setMaxTime("XXX"))
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideOutOfBoundNumbers")
+ void configureNetworkForAllControlBlocks_when_out_of_bound_numbers_should_return_error(Consumer setMalformedNumber) {
+ // Given
+ SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ CBCom cbCom = createCbCom();
+ setMalformedNumber.accept(cbCom.getVlans().getVlan().get(0));
+ //When
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
+ //Then
+ assertThat(sclReportItems).hasSize(1);
+ assertThat(sclReportItems.get(0)).extracting(SclReportItem::isError, SclReportItem::xpath)
+ .containsExactly(true, "Control Block Communication setting files");
+ assertThat(sclReportItems.get(0).message()).matches("Error in Control Block communication setting file: VLAN (ID|PRIORITY) must be between 0 and [0-9]+, but got : .*");
+ }
+
+ private static Stream provideOutOfBoundNumbers() {
+ return Stream.of(
+ Arguments.of((Consumer) tVlan -> tVlan.setVlanId("4096")), // VlanId > MAX_VLAN_ID
+ Arguments.of((Consumer) tVlan -> tVlan.setVlanId("-1")), // VlanId < 0
+ Arguments.of((Consumer) tVlan -> tVlan.setVlanPriority("8")), // VlanPriority > MAX_VLAN_PRIORITY
+ Arguments.of((Consumer) tVlan -> tVlan.setVlanPriority("-1")) // VlanPriority < 0
+ );
+ }
+
+ @Test
+ void configureNetworkForAllControlBlocks_when_missing_connectedAp_should_return_error() {
+ // Given
+ SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ scd.getCommunication().getSubNetwork().get(0).getConnectedAP().remove(0);
+ CBCom cbCom = createCbCom();
+ //When
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
+ //Then
+ assertThat(sclReportItems).hasSize(3);
+ assertThat(sclReportItems).extracting(SclReportItem::isError).containsOnly(true);
+ assertThat(sclReportItems).extracting(SclReportItem::message).containsOnly("Cannot configure communication for ControlBlock because no ConnectedAP found for AccessPoint");
+ assertThat(sclReportItems).extracting(SclReportItem::xpath).allMatch(xpath -> xpath.startsWith("""
+ /SCL/IED[@name="IED_NAME2"]/AccessPoint[@name="AP_NAME"]/Server/LDevice[@inst="LD_INST21"]/LN0/"""));
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideRemovePrivateInfo")
+ void configureNetworkForAllControlBlocks_when_missing_IED_privates_should_return_error(Consumer removePrivateInfo) {
+ // Given
+ SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
+ CBCom cbCom = createCbCom();
+ removePrivateInfo.accept(scd.getIED().get(1));
+ //When
+ List sclReportItems = controlBlockEditorService.configureNetworkForAllControlBlocks(scd, cbCom);
+ //Then
+ assertThat(sclReportItems).hasSize(3);
+ assertThat(sclReportItems).extracting(SclReportItem::isError, SclReportItem::xpath)
+ .containsOnly(Tuple.tuple(true, """
+ /SCL/IED[@name="IED_NAME2"]/AccessPoint[@name="AP_NAME"]/Server/LDevice[@inst="LD_INST21"]"""));
+ assertThat(sclReportItems).extracting(SclReportItem::message).allSatisfy(message -> assertThat(message).containsAnyOf("COMPAS-ICDHeader", "COMPAS-SystemVersion"));
+ }
+
+ private static Stream provideRemovePrivateInfo() {
+ return Stream.of(
+ Arguments.of((Consumer) tied -> PrivateUtils.removePrivates(tied, PrivateEnum.COMPAS_SYSTEM_VERSION)),
+ Arguments.of((Consumer) tied -> PrivateUtils.extractCompasPrivate(tied, TCompasSystemVersion.class).ifPresent(tCompasSystemVersion -> tCompasSystemVersion.setMainSystemVersion(null))),
+ Arguments.of((Consumer) tied -> PrivateUtils.extractCompasPrivate(tied, TCompasSystemVersion.class).ifPresent(tCompasSystemVersion -> tCompasSystemVersion.setMinorSystemVersion(null))),
+ Arguments.of((Consumer) tied -> PrivateUtils.removePrivates(tied, PrivateEnum.COMPAS_ICDHEADER)),
+ Arguments.of((Consumer) tied -> PrivateUtils.extractCompasPrivate(tied, TCompasICDHeader.class).ifPresent(tCompasICDHeader -> tCompasICDHeader.setIEDSystemVersioninstance(null)))
+ );
}
@Test
@@ -458,7 +614,7 @@ void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_controlBlocks_and_D
// Given
SCL scl = SclTestMarshaller.getSCLFromFile("/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml");
// When
- controlBlockService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl);
+ controlBlockEditorService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl);
// Then
SclRootAdapter scdRootAdapter = new SclRootAdapter(scl);
List lDevices = scdRootAdapter.streamIEDAdapters().flatMap(IEDAdapter::streamLDeviceAdapters).toList();
@@ -478,7 +634,7 @@ void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_controlBlocks_and_D
// Given
SCL scl = SclTestMarshaller.getSCLFromFile("/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml");
// When
- controlBlockService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl);
+ controlBlockEditorService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl);
// Then
SclRootAdapter scdRootAdapter = new SclRootAdapter(scl);
List lns = scdRootAdapter.streamIEDAdapters()
@@ -493,30 +649,70 @@ void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_controlBlocks_and_D
assertIsMarshallable(scl);
}
- public static Stream provideConfigureNetworkForAllControlBlocksErrors() {
- Settings settingsWithNullVlanId = new Settings(null, (byte) 1, newDurationInMilliSec(1), newDurationInMilliSec(2));
- Settings settings = new Settings(1, (byte) 1, newDurationInMilliSec(1), newDurationInMilliSec(2));
- return Stream.of(
- Arguments.of((ControlBlockNetworkSettings) controlBlockAdapter -> new SettingsOrError(null, null),
- RANGES_PER_CB_TYPE,
- "Cannot configure network for this ControlBlock because no settings was provided"),
- Arguments.of((ControlBlockNetworkSettings) controlBlockAdapter -> new SettingsOrError(null, "Custom error message"),
- RANGES_PER_CB_TYPE,
- "Cannot configure network for this ControlBlock because: Custom error message"),
- Arguments.of((ControlBlockNetworkSettings) controlBlockAdapter -> new SettingsOrError(settingsWithNullVlanId, null),
- RANGES_PER_CB_TYPE,
- "Cannot configure network for this ControlBlock because no Vlan Id was provided in the settings"),
- Arguments.of((ControlBlockNetworkSettings) controlBlockAdapter -> new SettingsOrError(settings, null),
- new RangesPerCbType(
- new NetworkRanges(GSE_APP_ID_MIN, GSE_APP_ID_MIN, GSE_MAC_ADDRESS_PREFIX + "00-FF", GSE_MAC_ADDRESS_PREFIX + "01-AA"),
- SMV_NETWORK_RANGES),
- "Cannot configure network for this ControlBlock because range of appId is exhausted"),
- Arguments.of((ControlBlockNetworkSettings) controlBlockAdapter -> new SettingsOrError(settings, null),
- new RangesPerCbType(
- new NetworkRanges(GSE_APP_ID_MIN, GSE_APP_ID_MIN + 10, GSE_MAC_ADDRESS_PREFIX + "00-FF", GSE_MAC_ADDRESS_PREFIX + "00-FF"),
- SMV_NETWORK_RANGES),
- "Cannot configure network for this ControlBlock because range of MAC Address is exhausted")
- );
+ private static TGSE getCommunicationGSE(SCL scd, String iedName, String cbName) {
+ return new SclRootAdapter(scd).findConnectedApAdapter(iedName, "AP_NAME").orElseThrow()
+ .getCurrentElem()
+ .getGSE().stream()
+ .filter(tgse -> cbName.equals(tgse.getCbName()))
+ .findFirst().orElseThrow();
+ }
+
+ private static TSMV getCommunicationSMV(SCL scd, String iedName, String cbName) {
+ return new SclRootAdapter(scd).findConnectedApAdapter(iedName, "AP_NAME").orElseThrow()
+ .getCurrentElem()
+ .getSMV().stream()
+ .filter(tsmv -> cbName.equals(tsmv.getCbName()))
+ .findFirst().orElseThrow();
+ }
+
+ private static CBCom createCbCom() {
+ CBCom cbCom = new CBCom();
+ cbCom.setMacRanges(new MacRanges());
+ cbCom.setAppIdRanges(new AppIdRanges());
+ cbCom.setVlans(new Vlans());
+ cbCom.getMacRanges().getMacRange().add(newRange(TCBType.GOOSE, "01-0C-CD-01-00-00", "01-0C-CD-01-01-FF"));
+ cbCom.getMacRanges().getMacRange().add(newRange(TCBType.SV, "01-0C-CD-04-00-00", "01-0C-CD-04-FF-FF"));
+ cbCom.getAppIdRanges().getAppIdRange().add(newRange(TCBType.GOOSE, "0000", "4000"));
+ cbCom.getAppIdRanges().getAppIdRange().add(newRange(TCBType.SV, "4000", "7FFF"));
+ cbCom.getVlans().getVlan().addAll(List.of(
+ newVlan(TCBType.GOOSE, TBayIntOrExt.BAY_INTERNAL, "301", "1"),
+ newVlan(TCBType.GOOSE, TBayIntOrExt.BAY_EXTERNAL, "302", "2"),
+ newVlan(TCBType.SV, TBayIntOrExt.BAY_INTERNAL, "303", "3"),
+ newVlan(TCBType.SV, TBayIntOrExt.BAY_EXTERNAL, "304", "4")
+ ));
+ return cbCom;
}
+ private static TRange newRange(TCBType tcbType, String start, String end) {
+ TRange macRangeGSE = new TRange();
+ macRangeGSE.setCBType(tcbType);
+ macRangeGSE.setStart(start);
+ macRangeGSE.setEnd(end);
+ return macRangeGSE;
+ }
+
+ private static TVlan newVlan(TCBType tcbType, TBayIntOrExt tBayIntOrExt, String vlanId, String vlanPriority) {
+ TVlan gseVlan = new TVlan();
+ gseVlan.setCBType(tcbType);
+ gseVlan.setXY("01.00");
+ gseVlan.setZW("009.001");
+ gseVlan.setIEDType(TIEDType.BCU);
+ gseVlan.setIEDRedundancy(TIEDRedundancy.A);
+ gseVlan.setIEDSystemVersionInstance("1");
+ gseVlan.setBayIntOrExt(tBayIntOrExt);
+ gseVlan.setVlanId(vlanId);
+ gseVlan.setVlanPriority(vlanPriority);
+ gseVlan.setMinTime("10");
+ gseVlan.setMaxTime("2000");
+ return gseVlan;
+ }
+
+ /**
+ * Help comparing TDurationInMilliSec
+ */
+ record SclDuration(String value, String unit, String multiplier) {
+ static SclDuration from(TDurationInMilliSec tDurationInMilliSec) {
+ return new SclDuration(tDurationInMilliSec.getValue().toString(), tDurationInMilliSec.getUnit(), tDurationInMilliSec.getMultiplier());
+ }
+ }
}
diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettingsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettingsTest.java
deleted file mode 100644
index 89450f8d6..000000000
--- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ControlBlockNetworkSettingsTest.java
+++ /dev/null
@@ -1,235 +0,0 @@
-// SPDX-FileCopyrightText: 2023 RTE FRANCE
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package org.lfenergy.compas.sct.commons.dto;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.EnumSource;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.junit.jupiter.params.provider.ValueSource;
-import org.lfenergy.compas.scl2007b4.model.SCL;
-import org.lfenergy.compas.scl2007b4.model.TDurationInMilliSec;
-import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.SettingsOrError;
-import org.lfenergy.compas.sct.commons.util.PrivateUtils;
-import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
-import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
-import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
-import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller;
-import org.lfenergy.compas.sct.commons.util.ControlBlockEnum;
-import org.lfenergy.compas.sct.commons.util.ControlBlockNetworkSettingsCsvHelper;
-import org.lfenergy.compas.sct.commons.util.CsvUtils;
-import org.lfenergy.compas.sct.commons.util.PrivateEnum;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringReader;
-import java.math.BigDecimal;
-import java.util.Objects;
-import java.util.function.Consumer;
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.Settings;
-import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.findControlBlock;
-import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.findIed;
-
-class ControlBlockNetworkSettingsTest {
-
- private ControlBlockNetworkSettings controlBlockNetworkSettings;
-
- @BeforeEach
- public void setUp() {
- String fileName = "ControlBlockCommunicationTemplates.csv";
- InputStream inputStream = Objects.requireNonNull(CsvUtils.class.getClassLoader().getResourceAsStream(fileName), "Resource not found: " + fileName);
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
- controlBlockNetworkSettings = new ControlBlockNetworkSettingsCsvHelper(inputStreamReader);
- }
-
- @ParameterizedTest
- @ValueSource(strings = {
- ";01.00;009.001;BCU;A;1;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;;009.001;BCU;A;1;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;01.00;;BCU;A;1;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;01.00;009.001;;A;1;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;01.00;009.001;BCU;;1;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;01.00;009.001;BCU;A;;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;01.00;009.001;BCU;A;1;;300;4;10;2000"
- })
- void constructor_when_csv_has_blank_criteria_cells_should_throw_exception(String row) {
- //Given
- StringReader stringReader = new StringReader(row);
- //When & Then
- assertThatThrownBy(() -> new ControlBlockNetworkSettingsCsvHelper(stringReader))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageStartingWith("At least one criteria is null in row ControlBlockNetworkSettingsCsvHelper.Row")
- .hasMessageContaining("=null,");
- }
-
- @ParameterizedTest
- @ValueSource(strings = {
- "GOOSE;01.00;009.001;BCU;A;XXX;BAY_INTERNAL;300;4;10;2000",
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;XXX;4;10;2000",
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;300;XXX;10;2000",
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;300;4;XXX;2000",
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;300;4;10;XXX"
- })
- void constructor_when_csv_has_malformed_numbers_should_throw_exception(String row) {
- //Given
- StringReader stringReader = new StringReader(row);
- //When & Then
- assertThatThrownBy(() -> new ControlBlockNetworkSettingsCsvHelper(stringReader))
- .isInstanceOf(NumberFormatException.class)
- .hasMessage("For input string: \"XXX\"");
- }
-
- @ParameterizedTest
- @ValueSource(strings = {
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;4096;4;10;2000", // VlanId > MAX_VLAN_ID
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;-1;4;10;2000", // VlanId < 0
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;300;8;10;2000", // VlanPriority > MAX_VLAN_PRIORITY
- "GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;300;-1;10;2000" // VlanPriority < 0
- })
- void constructor_when_csv_has_numbers_our_out_of_bound_should_throw_exception(String row) {
- //Given
- StringReader stringReader = new StringReader(row);
- //When & Then
- assertThatThrownBy(() -> new ControlBlockNetworkSettingsCsvHelper(stringReader))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessageContaining("must be between 0 and ");
- }
-
- @Test
- void constructor_when_unsupported_cbType_should_throw_exception() {
- //Given
- StringReader stringReader = new StringReader("CUSTOM_CB_TYPE;01.00;009.001;BCU;A;1;BAY_INTERNAL;1;4;10;2000");
- //When & Then
- assertThatThrownBy(() -> new ControlBlockNetworkSettingsCsvHelper(stringReader))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Unsupported Control Block Type : CUSTOM_CB_TYPE");
- }
-
- @Test
- void getNetworkSettings_should_return_settings_for_bay_internal_controlBlock() {
- //Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
- ControlBlockAdapter controlBlockAdapter = findControlBlock(scd, "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);
-
- //When
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
-
- //Then
- assertThat(settingsOrError.errorMessage()).isNull();
- Settings networkSettings = settingsOrError.settings();
- assertThat(networkSettings)
- .extracting(Settings::vlanId, Settings::vlanPriority)
- .containsExactly(300, (byte) 4);
- assertThat(networkSettings.minTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("10"));
- assertThat(networkSettings.maxTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("2000"));
- }
-
- @Test
- void getNetworkSettings_should_return_settings_for_bay_external_controlBlock() {
- //Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
- ControlBlockAdapter controlBlockAdapter = findControlBlock(scd, "IED_NAME3", "LD_INST31", "CB_LD_INST31_GSE", ControlBlockEnum.GSE);
-
- //When
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
-
- //Then
- assertThat(settingsOrError.errorMessage()).isNull();
- Settings networkSettings = settingsOrError.settings();
- assertThat(networkSettings)
- .extracting(Settings::vlanId, Settings::vlanPriority)
- .containsExactly(301, (byte) 5);
- assertThat(networkSettings.minTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("15"));
- assertThat(networkSettings.maxTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("5000"));
- }
-
- @Test
- void getNetworkSettings_should_return_vlanId_null_when_column_contains_none() {
- //Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
- ControlBlockAdapter controlBlockAdapter = findControlBlock(scd, "IED_NAME2", "LD_INST21", "CB_LD_INST21_SVI", ControlBlockEnum.SAMPLED_VALUE);
-
- //When
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
-
- //Then
- assertThat(settingsOrError.errorMessage()).isNull();
- Settings networkSettings = settingsOrError.settings();
- assertThat(networkSettings.vlanId()).isNull();
- assertThat(networkSettings.vlanPriority()).isNull();
- }
-
- @Test
- void getNetworkSettings_should_return_null_when_row_not_found_in_csv_file() {
- //Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- findIed(sclRootAdapter.getCurrentElem(), "IED_NAME2").getCompasSystemVersion().get().setMainSystemVersion("99.99");
- ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter.getCurrentElem(), "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);
-
- //When
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
-
- //Then
- assertThat(settingsOrError.errorMessage()).isEqualTo("No row found with these criteria Criteria[controlBlockEnum=GSE, systemVersionWithoutV=99.99.009.001, iedType=BCU, iedRedundancy=A, iedSystemVersionInstance=1, isBayInternal=true]");
- assertThat(settingsOrError.settings()).isNull();
- }
-
- @ParameterizedTest
- @EnumSource(value = PrivateEnum.class, mode = EnumSource.Mode.INCLUDE, names = {"COMPAS_ICDHEADER", "COMPAS_SYSTEM_VERSION"})
- void getNetworkSettings_should_return_null_when_missing_ied_private(PrivateEnum missingPrivate) {
- //Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
- SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
- PrivateUtils.removePrivates(findIed(sclRootAdapter.getCurrentElem(), "IED_NAME2").getCurrentElem(), missingPrivate);
- ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter.getCurrentElem(), "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);
-
- //When
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
-
- //Then
- assertThat(settingsOrError.errorMessage()).isEqualTo("No private %s found in this IED".formatted(missingPrivate.getPrivateType()));
- assertThat(settingsOrError.settings()).isNull();
- }
-
- @ParameterizedTest
- @MethodSource("provideInvalidCompasAttributes")
- void getNetworkSettings_should_return_null_when_missing_ied_private_attributes(Consumer transformIedPrivate) {
- //Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_controlblock_network_configuration.xml");
- ControlBlockAdapter controlBlockAdapter = findControlBlock(scd, "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);
- IEDAdapter iedAdapter = findIed(scd, "IED_NAME2");
- transformIedPrivate.accept(iedAdapter);
-
- //When
- SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
-
- //Then
- assertThat(settingsOrError.errorMessage()).startsWith("No row found with these criteria ");
- assertThat(settingsOrError.settings()).isNull();
- }
-
- private static Stream provideInvalidCompasAttributes() {
- return Stream.of(
- Arguments.of((Consumer) iedAdapter -> iedAdapter.getCompasICDHeader().get().setIEDType(null)),
- Arguments.of((Consumer) iedAdapter -> iedAdapter.getCompasICDHeader().get().setIEDredundancy(null)),
- Arguments.of((Consumer) iedAdapter -> iedAdapter.getCompasICDHeader().get().setIEDSystemVersioninstance(null)),
- Arguments.of((Consumer) iedAdapter -> iedAdapter.getCompasSystemVersion().get().setMainSystemVersion(null)),
- Arguments.of((Consumer) iedAdapter -> iedAdapter.getCompasSystemVersion().get().setMinorSystemVersion(null)),
- Arguments.of((Consumer) iedAdapter -> iedAdapter.getCompasSystemVersion().get().setMinorSystemVersion("1")) // Invalid format for MinorSystemVersion
- );
- }
-
-}
diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapterTest.java
index 2e419e3d4..2e1d29687 100644
--- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapterTest.java
+++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/ControlBlockAdapterTest.java
@@ -4,21 +4,18 @@
package org.lfenergy.compas.sct.commons.scl.ied;
-import org.assertj.core.groups.Tuple;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
-import org.lfenergy.compas.scl2007b4.model.*;
-import org.lfenergy.compas.sct.commons.dto.SclReportItem;
+import org.lfenergy.compas.scl2007b4.model.SCL;
+import org.lfenergy.compas.scl2007b4.model.TControl;
+import org.lfenergy.compas.scl2007b4.model.TControlWithIEDName;
+import org.lfenergy.compas.scl2007b4.model.TGSEControl;
import org.lfenergy.compas.sct.commons.scl.ln.LN0Adapter;
import org.lfenergy.compas.sct.commons.scl.ln.LNAdapter;
-import org.lfenergy.compas.sct.commons.testhelpers.SclHelper;
import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller;
import org.lfenergy.compas.sct.commons.util.ControlBlockEnum;
-import org.lfenergy.compas.sct.commons.util.SclConstructorHelper;
-import java.math.BigDecimal;
import java.util.List;
-import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.findLn;
@@ -64,80 +61,4 @@ void addTargetIfNotExists_should_add_target(){
.containsExactly("AP_NAME", "IED_NAME2", "LD_INST21", "1", List.of("ANCR"), "prefix");
}
- @Test
- @Tag("issue-321")
- void configureNetwork_should_add_GSE_element() {
- // Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scl-ln-adapter/scd_with_ln.xml");
- TConnectedAP connectedAP = SclHelper.addConnectedAp(scd, "SUB_NETWORK_NAME", "AP_NAME", "IED_NAME1");
- LN0Adapter ln0 = findLn0(scd, "IED_NAME1", "LD_INST11");
- // When
- ln0.createDataSetIfNotExists("datSet", ControlBlockEnum.GSE);
- // When
- ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists("cbName", "cbId", "datSet", ControlBlockEnum.GSE);
- // When
- Optional sclReportItem = controlBlockAdapter.configureNetwork(10L, "00-01-02-04-05", 11, (byte) 12, SclConstructorHelper.newDurationInMilliSec(3),
- SclConstructorHelper.newDurationInMilliSec(20));
- // Then
- assertThat(sclReportItem).isEmpty();
- assertThat(connectedAP.getGSE()).hasSize(1);
- TGSE gse = connectedAP.getGSE().get(0);
- assertThat(gse.getLdInst()).isEqualTo("LD_INST11");
- assertThat(gse.getMinTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("3"));
- assertThat(gse.getMaxTime()).extracting(TDurationInMilliSec::getUnit, TDurationInMilliSec::getMultiplier, TDurationInMilliSec::getValue)
- .containsExactly("s", "m", new BigDecimal("20"));
- assertThat(gse.getAddress().getP()).extracting(TP::getType, TP::getValue)
- .containsExactlyInAnyOrder(
- Tuple.tuple("APPID", "000A"),
- Tuple.tuple("MAC-Address", "00-01-02-04-05"),
- Tuple.tuple("VLAN-ID", "00B"),
- Tuple.tuple("VLAN-PRIORITY", "12")
- );
- }
-
- @Test
- @Tag("issue-321")
- void configureNetwork_should_add_SMV_element() {
- // Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scl-ln-adapter/scd_with_ln.xml");
- TConnectedAP connectedAP = SclHelper.addConnectedAp(scd, "SUB_NETWORK_NAME", "AP_NAME", "IED_NAME1");
- LN0Adapter ln0 = findLn0(scd, "IED_NAME1", "LD_INST11");
- // When
- ln0.createDataSetIfNotExists("datSet", ControlBlockEnum.SAMPLED_VALUE);
- // When
- ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists("cbName", "cbId", "datSet", ControlBlockEnum.SAMPLED_VALUE);
- // When
- Optional sclReportItem = controlBlockAdapter.configureNetwork(10L, "00-01-02-04-05", 11, (byte) 12, null, null);
- // Then
- assertThat(sclReportItem).isEmpty();
- assertThat(connectedAP.getSMV()).hasSize(1);
- TSMV smv = connectedAP.getSMV().get(0);
- assertThat(smv.getLdInst()).isEqualTo("LD_INST11");
- assertThat(smv.getAddress().getP()).extracting(TP::getType, TP::getValue)
- .containsExactlyInAnyOrder(
- Tuple.tuple("APPID", "000A"),
- Tuple.tuple("MAC-Address", "00-01-02-04-05"),
- Tuple.tuple("VLAN-ID", "00B"),
- Tuple.tuple("VLAN-PRIORITY", "12")
- );
- }
-
- @Test
- @Tag("issue-321")
- void configureNetwork_when_connectApNotFound_should_return_sclReportItem() {
- // Given
- SCL scd = SclTestMarshaller.getSCLFromFile("/scl-ln-adapter/scd_with_ln.xml");
- SclHelper.addConnectedAp(scd, "SUB_NETWORK_NAME", "AP_NAME", "IED_NAME2"); // ConnectedAp for IED_NAME2 instead of IED_NAME1
- LN0Adapter ln0 = findLn0(scd, "IED_NAME1", "LD_INST11");
- // When
- ln0.createDataSetIfNotExists("datSet", ControlBlockEnum.SAMPLED_VALUE);
- // When
- ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists("cbName", "cbId", "datSet", ControlBlockEnum.SAMPLED_VALUE);
- // When
- Optional sclReportItem = controlBlockAdapter.configureNetwork(10L, "00-01-02-04-05", 11, (byte) 12, null, null);
- // Then
- assertThat(sclReportItem).isPresent();
- }
-
}
diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnumTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnumTest.java
index 7aa300377..b3444fecb 100644
--- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnumTest.java
+++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/ControlBlockEnumTest.java
@@ -7,41 +7,44 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.lfenergy.compas.scl2007b4.model.*;
+import org.lfenergy.compas.sct.commons.model.cbcom.TCBType;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.lfenergy.compas.sct.commons.util.ControlBlockEnum.from;
class ControlBlockEnumTest {
@ParameterizedTest
@MethodSource("provideFromTServiceType")
- void from_should_map_ServiceType_to_ControlBlockEnumTest(TServiceType tServiceType, ControlBlockEnum expected) {
+ void from_TServiceType_should_map_ServiceType_to_ControlBlockEnumTest(TServiceType tServiceType, ControlBlockEnum expected) {
//Given : parameter
//When
- ControlBlockEnum result = ControlBlockEnum.from(tServiceType);
+ ControlBlockEnum result = from(tServiceType);
//Then
assertThat(result).isEqualTo(expected);
}
@Test
- void from_POOL_should_throw_exception() {
+ void from_TServiceType_POOL_should_throw_exception() {
//Given
TServiceType pollServiceType = TServiceType.POLL;
//When & Then
- assertThatThrownBy(() -> ControlBlockEnum.from(pollServiceType))
+ assertThatThrownBy(() -> from(pollServiceType))
.isInstanceOf(IllegalArgumentException.class);
}
@ParameterizedTest
@MethodSource("provideFromTControlClass")
- void from_should_map_Class_to_ControlBlockEnumTest(Class extends TControl> tControlClass, ControlBlockEnum expected) {
+ void from_TControl_should_map_Class_to_ControlBlockEnumTest(Class extends TControl> tControlClass, ControlBlockEnum expected) {
//Given : parameter
//When
- ControlBlockEnum result = ControlBlockEnum.from(tControlClass);
+ ControlBlockEnum result = from(tControlClass);
//Then
assertThat(result).isEqualTo(expected);
}
@@ -63,4 +66,30 @@ public static Stream provideFromTServiceType() {
);
}
+ @ParameterizedTest
+ @MethodSource("provideFromTCBType")
+ public void from_TCBType_when_GOOSE_or_SV_should_succeed(TCBType tcbType, ControlBlockEnum expectedControlBlockEnum){
+ // Given : parameter
+ // When
+ ControlBlockEnum result = from(tcbType);
+ // Then
+ assertThat(result).isEqualTo(expectedControlBlockEnum);
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = TCBType.class, mode = EnumSource.Mode.EXCLUDE, names = {"GOOSE", "SV"})
+ public void from_TCBType_when_unsupported_TCBType_should_throw_exception(TCBType tcbType){
+ // Given : parameter
+ // When & Then
+ assertThatThrownBy(() -> from(tcbType))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Unsupported TCBType: " + tcbType.name());
+ }
+
+ public static Stream provideFromTCBType() {
+ return Stream.of(
+ Arguments.of(TCBType.GOOSE, ControlBlockEnum.GSE),
+ Arguments.of(TCBType.SV, ControlBlockEnum.SAMPLED_VALUE)
+ );
+ }
}
diff --git a/sct-commons/src/test/resources/ControlBlockCommunicationTemplates.csv b/sct-commons/src/test/resources/ControlBlockCommunicationTemplates.csv
deleted file mode 100644
index 5d149af69..000000000
--- a/sct-commons/src/test/resources/ControlBlockCommunicationTemplates.csv
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-FileCopyrightText: 2022 RTE FRANCE
-#
-# SPDX-License-Identifier: Apache-2.0
-
-#CB Type;X.Y;Z.W;IedType;IedRedundancy;IedSystemVersionInstance;Bay Internal OR External;VLAN-ID;VLAN-PRIORITY;MINTIME;MAXTIME
-GOOSE;01.00;009.001;BCU;A;1;BAY_INTERNAL;300;4;10;2000
-SV;01.00;009.001;BCU;A;1;BAY_INTERNAL;None;None;;
-GOOSE;01.00;009.001;BCU;A;1;BAY_EXTERNAL;301;5;15;5000
-SV;01.00;009.001;BCU;A;1;BAY_EXTERNAL;None;None;;