Skip to content

Commit

Permalink
feat(#259): add criteria iedSystemVersionInstance in ControlBlockNetw…
Browse files Browse the repository at this point in the history
…orkSettingsCsvHelper

Signed-off-by: massifben <105049157+massifben@users.noreply.github.com>
  • Loading branch information
massifben committed Mar 16, 2023
1 parent 62aeade commit 3d6cdae
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ public interface ControlBlockNetworkSettings {
* vlanPriority will be ignored when vlanId is null.
*
* @param controlBlockAdapter ControlBlock for which we want to configure the communication section
* @return network settings : All fields are optional (meaning fields can be null).
* When the return value itself is null, the communication section will not be configured for this ControlBlock.
* @return network settings to use to configure Communication section for this ControlBlock.
* An error message can be provided (i.e. errorMessage not null) or a null settings, in order not to configure the ControlBlock.
*/
Settings getNetworkSettings(ControlBlockAdapter controlBlockAdapter);
SettingsOrError getNetworkSettings(ControlBlockAdapter controlBlockAdapter);

/**
* Network settings for ControlBlock communication
Expand All @@ -40,6 +40,15 @@ public interface ControlBlockNetworkSettings {
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
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader;
import org.lfenergy.compas.scl2007b4.model.TIED;
import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.Settings;
import org.lfenergy.compas.sct.commons.dto.SclReport;
import org.lfenergy.compas.sct.commons.dto.SclReportItem;
import org.lfenergy.compas.sct.commons.exception.ScdException;
Expand All @@ -27,8 +26,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.NetworkRanges;
import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.RangesPerCbType;
import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.*;

@UtilityClass
public class ExtRefService {
Expand Down Expand Up @@ -202,8 +200,12 @@ private static List<SclReportItem> configureNetworkForControlBlocks(SCL scd, Con
}

private static Optional<SclReportItem> configureControlBlockNetwork(ControlBlockNetworkSettings controlBlockNetworkSettings, PrimitiveIterator.OfLong appIdIterator, Iterator<String> macAddressIterator, ControlBlockAdapter controlBlockAdapter) {
Settings settings = controlBlockNetworkSettings.getNetworkSettings(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"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,18 @@
package org.lfenergy.compas.sct.commons.util;

import com.opencsv.bean.CsvBindByPosition;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader;
import org.lfenergy.compas.scl2007b4.model.TCompasIEDRedundancy;
import org.lfenergy.compas.scl2007b4.model.TCompasIEDType;
import org.lfenergy.compas.scl2007b4.model.TDurationInMilliSec;
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;

/**
Expand All @@ -38,7 +34,7 @@ public class ControlBlockNetworkSettingsCsvHelper implements ControlBlockNetwork
private static final int MAX_VLAN_PRIORITY = 7;
private static final String NONE = "none";

private final Map<Criteria, Settings> settings;
private final Map<Criteria, Settings> allSettings;

/**
* Constructor
Expand All @@ -48,7 +44,7 @@ public class ControlBlockNetworkSettingsCsvHelper implements ControlBlockNetwork
* @param csvSource a reader that provides the data as CSV. For example :
*/
public ControlBlockNetworkSettingsCsvHelper(Reader csvSource) {
settings = readCsvFile(csvSource);
allSettings = readCsvFile(csvSource);
}

private Map<Criteria, Settings> readCsvFile(Reader csvSource) {
Expand All @@ -61,17 +57,29 @@ private Map<Criteria, Settings> readCsvFile(Reader csvSource) {
}

@Override
public Settings getNetworkSettings(ControlBlockAdapter controlBlockAdapter) {
public SettingsOrError getNetworkSettings(ControlBlockAdapter controlBlockAdapter) {
ControlBlockEnum controlBlockEnum = controlBlockAdapter.getControlBlockEnum();
IEDAdapter iedAdapter = controlBlockAdapter.getParentIedAdapter();
String systemVersion = iedAdapter.getCompasSystemVersion()
.map(version -> version.getMainSystemVersion() + "." + version.getMinorSystemVersion())
.orElse(null);
Optional<TCompasSystemVersion> compasSystemVersion = iedAdapter.getCompasSystemVersion();
if (compasSystemVersion.isEmpty()) {
return new SettingsOrError(null, "No private COMPAS-SystemVersion found in this IED");
}
String systemVersion = compasSystemVersion.get().getMainSystemVersion() + "." + compasSystemVersion.get().getMinorSystemVersion();
String systemVersionWithoutV = removeVFromSystemVersion(systemVersion);
TCompasIEDType iedType = iedAdapter.getCompasICDHeader().map(TCompasICDHeader::getIEDType).orElse(null);
TCompasIEDRedundancy iedRedundancy = iedAdapter.getCompasICDHeader().map(TCompasICDHeader::getIEDredundancy).orElse(null);
Optional<TCompasICDHeader> 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");
return findSettings(new Criteria(controlBlockEnum, systemVersionWithoutV, iedType, iedRedundancy, isBayInternal));

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) {
Expand All @@ -81,7 +89,7 @@ private Settings findSettings(Criteria criteria) {
|| criteria.iedRedundancy() == null) {
return null;
}
return settings.get(criteria);
return allSettings.get(criteria);
}

private static String removeVFromSystemVersion(String systemVersion) {
Expand All @@ -100,9 +108,11 @@ private static Criteria rowToCriteria(Row row) {
|| 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 (cbType, xy, zw, iedType, bindingType) is blank");
throw new IllegalArgumentException("At least one criteria is null in row " + row);
}
ControlBlockEnum controlBlockEnum = switch (row.cbType) {
case "GOOSE" -> ControlBlockEnum.GSE;
Expand All @@ -114,6 +124,7 @@ private static Criteria rowToCriteria(Row row) {
row.xy + "." + row.zw,
TCompasIEDType.fromValue(row.iedType),
TCompasIEDRedundancy.fromValue(row.iedRedundancy),
new BigInteger(row.iedSystemVersionInstance),
row.bindingType.equals("BAY_INTERNAL")
);
}
Expand Down Expand Up @@ -160,13 +171,11 @@ private record Criteria(
String systemVersionWithoutV,
TCompasIEDType iedType,
TCompasIEDRedundancy iedRedundancy,
BigInteger iedSystemVersionInstance,
boolean isBayInternal) {
}

@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
@Data
public static class Row {
@CsvBindByPosition(position = 0)
private String cbType;
Expand All @@ -179,14 +188,16 @@ public static class Row {
@CsvBindByPosition(position = 4)
private String iedRedundancy;
@CsvBindByPosition(position = 5)
private String bindingType;
private String iedSystemVersionInstance;
@CsvBindByPosition(position = 6)
private String vlanId;
private String bindingType;
@CsvBindByPosition(position = 7)
private String vlanPriority;
private String vlanId;
@CsvBindByPosition(position = 8)
private String minTime;
private String vlanPriority;
@CsvBindByPosition(position = 9)
private String minTime;
@CsvBindByPosition(position = 10)
private String maxTime;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
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.scl.PrivateService;
import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
Expand Down Expand Up @@ -97,9 +98,11 @@ void getNetworkSettings_should_return_settings_for_bay_internal_controlBlock() {
ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter, "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);

//When
ControlBlockNetworkSettings.Settings networkSettings = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
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);
Expand All @@ -117,9 +120,11 @@ void getNetworkSettings_should_return_settings_for_bay_external_controlBlock() {
ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter, "IED_NAME3", "LD_INST31", "CB_LD_INST31_GSE", ControlBlockEnum.GSE);

//When
ControlBlockNetworkSettings.Settings networkSettings = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
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);
Expand All @@ -137,9 +142,11 @@ void getNetworkSettings_should_return_vlanId_null_when_column_contains_none() {
ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter, "IED_NAME2", "LD_INST21", "CB_LD_INST21_SVI", ControlBlockEnum.SAMPLED_VALUE);

//When
ControlBlockNetworkSettings.Settings networkSettings = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);

//Then
assertThat(settingsOrError.errorMessage()).isNull();
Settings networkSettings = settingsOrError.settings();
assertThat(networkSettings.vlanId()).isNull();
assertThat(networkSettings.vlanPriority()).isNull();
}
Expand All @@ -153,26 +160,28 @@ void getNetworkSettings_should_return_null_when_row_not_found_in_csv_file() {
ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter, "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);

//When
ControlBlockNetworkSettings.Settings networkSettings = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);

//Then
assertThat(networkSettings).isNull();
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 privateEnum) {
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);
PrivateService.removePrivates(findIed(sclRootAdapter, "IED_NAME2").getCurrentElem(), privateEnum);
PrivateService.removePrivates(findIed(sclRootAdapter, "IED_NAME2").getCurrentElem(), missingPrivate);
ControlBlockAdapter controlBlockAdapter = findControlBlock(sclRootAdapter, "IED_NAME2", "LD_INST21", "CB_LD_INST21_GSI", ControlBlockEnum.GSE);

//When
ControlBlockNetworkSettings.Settings networkSettings = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
SettingsOrError settingsOrError = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);

//Then
assertThat(networkSettings).isNull();
assertThat(settingsOrError.errorMessage()).isEqualTo("No private %s found in this IED".formatted(missingPrivate.getPrivateType()));
assertThat(settingsOrError.settings()).isNull();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ void configureNetworkForAllControlBlocks_should_create_GSE_and_SMV_elements() {

TDurationInMilliSec minTime = newDurationInMilliSec(10);
TDurationInMilliSec maxTime = newDurationInMilliSec(2000);
ControlBlockNetworkSettings controlBlockNetworkSettings = controlBlockAdapter -> new Settings(0x1D6, (byte) 4, minTime, maxTime);
ControlBlockNetworkSettings controlBlockNetworkSettings = controlBlockAdapter -> new SettingsOrError(new Settings(0x1D6, (byte) 4, minTime, maxTime), null);

// When
SclReport sclReport = ExtRefService.configureNetworkForAllControlBlocks(scd, controlBlockNetworkSettings, RANGES_PER_CB_TYPE);
Expand Down Expand Up @@ -455,7 +455,7 @@ void configureNetworkForAllControlBlocks_should_create_GSE_with_incremental_appi

TDurationInMilliSec minTime = newDurationInMilliSec(10);
TDurationInMilliSec maxTime = newDurationInMilliSec(2000);
ControlBlockNetworkSettings controlBlockNetworkSettings = controlBlockAdapter -> new Settings(0x1D6, (byte) 4, minTime, maxTime);
ControlBlockNetworkSettings controlBlockNetworkSettings = controlBlockAdapter -> new SettingsOrError(new Settings(0x1D6, (byte) 4, minTime, maxTime), null);
// When
SclReport sclReport = ExtRefService.configureNetworkForAllControlBlocks(scd, controlBlockNetworkSettings, RANGES_PER_CB_TYPE);
// Then
Expand Down Expand Up @@ -487,18 +487,21 @@ public static Stream<Arguments> 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 -> null,
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 -> settingsWithNullVlanId,
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 -> 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 -> settings,
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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#
# SPDX-License-Identifier: Apache-2.0

#CB Type;X.Y;Z.W;IedType;IedRedundancy;Bay Internal OR External;VLAN-ID;VLAN-PRIORITY;MINTIME;MAXTIME
GOOSE;01.00;009.001;BCU;A;BAY_INTERNAL;300;4;10;2000
SV;01.00;009.001;BCU;A;BAY_INTERNAL;None;None;;
GOOSE;01.00;009.001;BCU;A;BAY_EXTERNAL;301;5;15;5000
SV;01.00;009.001;BCU;A;BAY_EXTERNAL;None;None;;
#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;;
Loading

0 comments on commit 3d6cdae

Please sign in to comment.