Skip to content

Commit 7f6dbed

Browse files
authored
feat(86): RSR-435 - set extRef.srcXXX attribute after creating controlBlocks (#220)
Signed-off-by: massifben <[email protected]>
1 parent 9de6a51 commit 7f6dbed

File tree

4 files changed

+102
-38
lines changed

4 files changed

+102
-38
lines changed

sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/InputsAdapter.java

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,26 @@ public class InputsAdapter extends SclElementAdapter<LN0Adapter, TInputs> {
4242
"LDevice with same inst attribute in source IED %s";
4343
private static final String MESSAGE_SOURCE_LN_NOT_FOUND = "The signal ExtRef lninst, doName or daName does not match any " +
4444
"source in LDevice %s";
45-
private static final String MESSAGE_SERVICE_TYPE_MISSING_ON_EXTREF = "The signal ExtRef is missing ServiceType attribute";
45+
private static final String MESSAGE_SERVICE_TYPE_MISSING = "The signal ExtRef is missing ServiceType attribute";
4646
private static final String MESSAGE_INVALID_SERVICE_TYPE = "The signal ExtRef ServiceType attribute is unexpected : %s";
47-
private static final String MESSAGE_IED_IS_MISSING_PRIVATE_COMPAS_BAY_UUID = "IED is missing Private/compas:Bay@UUID attribute";
48-
private static final String MESSAGE_REPORT_EXTREF_DESC_MALFORMED = "ExtRef.serviceType=Report but ExtRef.desc attribute is malformed";
47+
private static final String MESSAGE_IED_MISSING_COMPAS_BAY_UUID = "IED is missing Private/compas:Bay@UUID attribute";
48+
private static final String MESSAGE_EXTREF_DESC_MALFORMED = "ExtRef.serviceType=Report but ExtRef.desc attribute is malformed";
49+
private static final String MESSAGE_LDEVICE_STATUS_UNDEFINED = "The LDevice status is undefined";
50+
private static final String MESSAGE_LDEVICE_STATUS_NEITHER_ON_NOR_OFF = "The LDevice status is neither \"on\" nor \"off\"";
51+
private static final String MESSAGE_EXTREF_IEDNAME_DOES_NOT_MATCH_ANY_SYSTEM_VERSION_UUID = "The signal ExtRef iedName does not match any " +
52+
"IED/Private/compas:ICDHeader@ICDSystemVersionUUID";
53+
private static final String MESSAGE_SOURCE_LDEVICE_STATUS_UNDEFINED = "The signal ExtRef source LDevice %s status is undefined";
54+
private static final String MESSAGE_SOURCE_LDEVICE_STATUS_NEITHER_ON_NOR_OFF = "The signal ExtRef source LDevice %s status is neither \"on\" nor \"off\"";
55+
private static final String MESSAGE_SOURCE_LDEVICE_STATUS_OFF = "The signal ExtRef source LDevice %s status is off";
56+
private static final String MESSAGE_SOURCE_IED_NOT_FOUND = "Source IED not found in SCD";
57+
private static final String MESSAGE_SOURCE_IED_MISSING_COMPAS_BAY_UUID = "Source IED is missing Private/compas:Bay@UUID attribute";
58+
private static final String MESSAGE_UNABLE_TO_CREATE_DATASET_OR_CONTROLBLOCK = "Could not create DataSet or ControlBlock for this ExtRef : ";
59+
private static final String MESSAGE_POLL_SERVICE_TYPE_NOT_SUPPORTED = "only GOOSE, SMV and REPORT ServiceType are allowed";
60+
4961
private static final int EXTREF_DESC_DA_NAME_POSITION = -2;
50-
private static final String EXTREF_DESC_DELIMITER = "_";
62+
private static final String ATTRIBUTE_VALUE_SEPARATOR = "_";
63+
private static final String DATASET_NAME_PREFIX = "DS" + ATTRIBUTE_VALUE_SEPARATOR;
64+
private static final String CONTROLBLOCK_NAME_PREFIX = "CB" + ATTRIBUTE_VALUE_SEPARATOR;
5165

5266
/**
5367
* Constructor
@@ -82,7 +96,7 @@ protected String elementXPath() {
8296
public List<SclReportItem> updateAllExtRefIedNames(Map<String, IEDAdapter> icdSystemVersionToIed) {
8397
Optional<String> optionalLDeviceStatus = getLDeviceAdapter().getLDeviceStatus();
8498
if (optionalLDeviceStatus.isEmpty()) {
85-
return List.of(getLDeviceAdapter().buildFatalReportItem("The LDevice status is undefined"));
99+
return List.of(getLDeviceAdapter().buildFatalReportItem(MESSAGE_LDEVICE_STATUS_UNDEFINED));
86100
}
87101
String lDeviceStatus = optionalLDeviceStatus.get();
88102
return switch (lDeviceStatus) {
@@ -99,7 +113,7 @@ yield getExtRefs().stream()
99113
getExtRefs().forEach(this::clearBinding);
100114
yield Collections.emptyList();
101115
}
102-
default -> List.of(getLDeviceAdapter().buildFatalReportItem("The LDevice status is neither \"on\" nor \"off\""));
116+
default -> List.of(getLDeviceAdapter().buildFatalReportItem(MESSAGE_LDEVICE_STATUS_NEITHER_ON_NOR_OFF));
103117
};
104118
}
105119

@@ -148,8 +162,7 @@ private List<TExtRef> getExtRefs() {
148162

149163
private Optional<SclReportItem> validateExtRefSource(TExtRef extRef, IEDAdapter sourceIed) {
150164
if (sourceIed == null) {
151-
return warningReportItem(extRef, "The signal ExtRef iedName does not match any " +
152-
"IED/Private/compas:ICDHeader@ICDSystemVersionUUID");
165+
return warningReportItem(extRef, MESSAGE_EXTREF_IEDNAME_DOES_NOT_MATCH_ANY_SYSTEM_VERSION_UUID);
153166
}
154167
Optional<LDeviceAdapter> optionalSourceLDevice = sourceIed.findLDeviceAdapterByLdInst(extRef.getLdInst());
155168
if (optionalSourceLDevice.isEmpty()) {
@@ -161,16 +174,16 @@ private Optional<SclReportItem> validateExtRefSource(TExtRef extRef, IEDAdapter
161174
}
162175
Optional<String> optionalSourceLDeviceStatus = sourceLDevice.getLDeviceStatus();
163176
if (optionalSourceLDeviceStatus.isEmpty()) {
164-
return fatalReportItem(extRef, String.format("The signal ExtRef source LDevice %s status is undefined",
177+
return fatalReportItem(extRef, String.format(MESSAGE_SOURCE_LDEVICE_STATUS_UNDEFINED,
165178
sourceLDevice.getXPath()));
166179
}
167180
return optionalSourceLDeviceStatus.map(sourceLDeviceStatus ->
168181
switch (sourceLDeviceStatus) {
169-
case OFF -> SclReportItem.warning(extRefXPath(extRef.getDesc()), String.format("The signal ExtRef source LDevice %s status is off",
182+
case OFF -> SclReportItem.warning(extRefXPath(extRef.getDesc()), String.format(MESSAGE_SOURCE_LDEVICE_STATUS_OFF,
170183
sourceLDevice.getXPath()));
171184
case ON -> null;
172185
default -> SclReportItem.fatal(extRefXPath(extRef.getDesc()),
173-
String.format("The signal ExtRef source LDevice %s status is neither \"on\" nor \"off\"",
186+
String.format(MESSAGE_SOURCE_LDEVICE_STATUS_NEITHER_ON_NOR_OFF,
174187
sourceLDevice.getXPath()));
175188
});
176189
}
@@ -249,7 +262,7 @@ public List<SclReportItem> updateAllSourceDataSetsAndControlBlocks() {
249262
List<TCompasFlow> compasFlows = PrivateService.extractCompasPrivates(currentElem, TCompasFlow.class);
250263
String currentBayUuid = getIedAdapter().getPrivateCompasBay().map(TCompasBay::getUUID).orElse(null);
251264
if (StringUtils.isBlank(currentBayUuid)) {
252-
return List.of(getIedAdapter().buildFatalReportItem(MESSAGE_IED_IS_MISSING_PRIVATE_COMPAS_BAY_UUID));
265+
return List.of(getIedAdapter().buildFatalReportItem(MESSAGE_IED_MISSING_COMPAS_BAY_UUID));
253266
}
254267
return getExtRefs().stream()
255268
.filter(this::areBindingAttributesPresent)
@@ -281,18 +294,18 @@ private boolean areBindingAttributesPresent(TExtRef tExtRef) {
281294

282295
private Optional<SclReportItem> updateSourceDataSetsAndControlBlocks(TExtRef extRef, String targetBayUuid) {
283296
if (extRef.getServiceType() == null) {
284-
return fatalReportItem(extRef, MESSAGE_SERVICE_TYPE_MISSING_ON_EXTREF);
297+
return fatalReportItem(extRef, MESSAGE_SERVICE_TYPE_MISSING);
285298
}
286299
Optional<IEDAdapter> optionalSrcIedAdapter = getSclRootAdapter().findIedAdapterByName(extRef.getIedName());
287300
if (optionalSrcIedAdapter.isEmpty()) {
288-
return fatalReportItem(extRef, "Source IED not found in SCD");
301+
return fatalReportItem(extRef, MESSAGE_SOURCE_IED_NOT_FOUND);
289302
}
290303
IEDAdapter sourceIed = optionalSrcIedAdapter.get();
291304
Optional<String> sourceIedBayUuid = sourceIed.getPrivateCompasBay()
292305
.map(TCompasBay::getUUID)
293306
.filter(StringUtils::isNotBlank);
294307
if (sourceIedBayUuid.isEmpty()) {
295-
return fatalReportItem(extRef, "Source IED is missing Private/compas:Bay@UUID attribute");
308+
return fatalReportItem(extRef, MESSAGE_SOURCE_IED_MISSING_COMPAS_BAY_UUID);
296309
}
297310

298311
boolean isBayInternal = targetBayUuid.equals(sourceIedBayUuid.get());
@@ -315,43 +328,56 @@ private Optional<SclReportItem> updateSourceDataSetsAndControlBlocks(TExtRef ext
315328
try {
316329
sourceDas.forEach(sourceDa -> {
317330
String datasetSuffix = generateDataSetSuffix(extRef, sourceDa, isBayInternal);
318-
createDataSetWithFCDA(extRef, sourceLDevice, sourceDa, datasetSuffix);
319-
createControlBlockWithTarget(extRef, sourceLDevice, sourceDa, datasetSuffix);
331+
String dataSetName = DATASET_NAME_PREFIX + datasetSuffix;
332+
String cbName = CONTROLBLOCK_NAME_PREFIX + datasetSuffix;
333+
createDataSetWithFCDA(extRef, sourceLDevice, sourceDa, dataSetName);
334+
createControlBlockWithTarget(extRef, sourceLDevice, sourceDa, cbName, dataSetName);
335+
setExtRefSrcAttributes(extRef, cbName);
320336
});
321337
} catch (ScdException e) {
322338
// ScdException can be thrown if AccessPoint does not have DataSet/ControlBlock creation capability
323339
log.error(e.getMessage(), e);
324-
return fatalReportItem(extRef, "Could not create DataSet for this ExtRef : " + e.getMessage());
340+
return fatalReportItem(extRef, MESSAGE_UNABLE_TO_CREATE_DATASET_OR_CONTROLBLOCK + e.getMessage());
325341
}
326342
return Optional.empty();
327343
}
328344

329-
private void createDataSetWithFCDA(TExtRef extRef, LDeviceAdapter sourceLDevice, ResumedDataTemplate sourceDa, String datasetSuffix) {
330-
DataSetAdapter dataSetAdapter = sourceLDevice.getLN0Adapter().createDataSetIfNotExists("DS_" + datasetSuffix, ControlBlockEnum.from(extRef.getServiceType()));
345+
private void createDataSetWithFCDA(TExtRef extRef, LDeviceAdapter sourceLDevice, ResumedDataTemplate sourceDa, String dataSetName) {
346+
DataSetAdapter dataSetAdapter = sourceLDevice.getLN0Adapter().createDataSetIfNotExists(dataSetName, ControlBlockEnum.from(extRef.getServiceType()));
331347
String fcdaDaName = extRef.getServiceType() == TServiceType.REPORT ? null : sourceDa.getDaRef();
332348
String fcdaLnClass = extRef.getLnClass().stream().findFirst().orElse(null);
333349
dataSetAdapter.createFCDAIfNotExists(extRef.getLdInst(), extRef.getPrefix(), fcdaLnClass, extRef.getLnInst(),
334-
sourceDa.getDoRef(), fcdaDaName, sourceDa.getFc());
350+
sourceDa.getDoRef(),
351+
fcdaDaName,
352+
sourceDa.getFc());
335353
}
336354

337-
private void createControlBlockWithTarget(TExtRef extRef, LDeviceAdapter sourceLDevice, ResumedDataTemplate sourceDa, String datasetSuffix) {
338-
String cbName = "CB_" + datasetSuffix;
355+
private void createControlBlockWithTarget(TExtRef extRef, LDeviceAdapter sourceLDevice, ResumedDataTemplate sourceDa, String cbName, String datSet) {
339356
String cbId = generateControlBlockId(cbName, sourceLDevice.getLdName(), getParentAdapter());
340-
ControlBlockAdapter controlBlockAdapter = sourceLDevice.getLN0Adapter().createControlBlockIfNotExists(cbName, cbId, "DS_" + datasetSuffix, ControlBlockEnum.from(extRef.getServiceType()));
357+
ControlBlockAdapter controlBlockAdapter = sourceLDevice.getLN0Adapter().createControlBlockIfNotExists(cbName, cbId, datSet, ControlBlockEnum.from(extRef.getServiceType()));
341358
if (sourceDa.getFc() != TFCEnum.ST && controlBlockAdapter.getCurrentElem() instanceof TReportControl tReportControl){
342359
tReportControl.getTrgOps().setDchg(false);
343360
tReportControl.getTrgOps().setQchg(false);
344361
}
345362
controlBlockAdapter.addTargetIfNotExists(getLNAdapter());
346363
}
347364

365+
private void setExtRefSrcAttributes(TExtRef extRef, String cbName) {
366+
extRef.setSrcCBName(cbName);
367+
extRef.setSrcLDInst(extRef.getLdInst());
368+
// srcPrefix, srcLNInst and srcLNClass are set to empty because ControlBlock is created in LN0
369+
extRef.setSrcPrefix(null);
370+
extRef.setSrcLNInst(null);
371+
extRef.unsetSrcLNClass();
372+
}
373+
348374
private static String generateDataSetSuffix(TExtRef extRef, ResumedDataTemplate sourceDa, boolean isBayInternal) {
349-
return extRef.getLdInst() + "_"
375+
return extRef.getLdInst() + ATTRIBUTE_VALUE_SEPARATOR
350376
+ switch (extRef.getServiceType()) {
351377
case GOOSE -> "G" + ((sourceDa.getFc() == TFCEnum.ST) ? "S" : "M");
352378
case SMV -> "SV";
353379
case REPORT -> (sourceDa.getFc() == TFCEnum.ST) ? "DQC" : "CYC";
354-
case POLL -> throw new IllegalArgumentException("only GOOSE, SMV and REPORT ServiceType are allowed");
380+
case POLL -> throw new IllegalArgumentException(MESSAGE_POLL_SERVICE_TYPE_NOT_SUPPORTED);
355381
}
356382
+ (isBayInternal ? "I" : "E");
357383
}
@@ -379,9 +405,9 @@ private Optional<SclReportItem> removeFilteredSourceDas(TExtRef extRef, final Se
379405
}
380406

381407
private Optional<SclReportItem> removeFilterSourceDaForReport(TExtRef extRef, Set<ResumedDataTemplate> sourceDas) {
382-
String daName = Utils.extractField(extRef.getDesc(), EXTREF_DESC_DELIMITER, EXTREF_DESC_DA_NAME_POSITION);
408+
String daName = Utils.extractField(extRef.getDesc(), ATTRIBUTE_VALUE_SEPARATOR, EXTREF_DESC_DA_NAME_POSITION);
383409
if (StringUtils.isBlank(daName)) {
384-
return fatalReportItem(extRef, MESSAGE_REPORT_EXTREF_DESC_MALFORMED);
410+
return fatalReportItem(extRef, MESSAGE_EXTREF_DESC_MALFORMED);
385411
}
386412
sourceDas.removeIf(resumedDataTemplate -> !resumedDataTemplate.getDaName().toString().equals(daName));
387413
return Optional.empty();

sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ExtRefServiceTest.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.lfenergy.compas.sct.commons.testhelpers.MarshallerWrapper;
2222
import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller;
2323

24+
import java.util.Collections;
2425
import java.util.List;
2526
import java.util.Optional;
2627
import java.util.stream.Stream;
@@ -34,7 +35,7 @@
3435
class ExtRefServiceTest {
3536

3637
@Test
37-
void updateAllExtRefIedNames_should_update_iedName_and_ExtRefiedName() {
38+
void updateAllExtRefIedNames_should_update_iedName_and_ExtRefIedName() {
3839
// Given : An ExtRef with a matching compas:Flow
3940
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-iedname/scd_set_extref_iedname_success.xml");
4041
// When
@@ -240,7 +241,6 @@ void createDataSetAndControlBlocks_should_create_ControlBlocks() {
240241
SclReport sclReport = ExtRefService.createDataSetAndControlBlocks(scd);
241242
// Then
242243
assertThat(sclReport.getSclReportItems()).isEmpty();
243-
assertThat(streamAllDataSets(sclReport.getSclRootAdapter())).hasSize(6);
244244

245245
// Check ControlBlock names, id and datSet
246246
assertControlBlockExists(sclReport, "IED_NAME2", "LD_INST21", "CB_LD_INST21_CYCI", "DS_LD_INST21_CYCI", "IED_NAME2LD_INST21/LLN0.CB_LD_INST21_CYCI", REPORT);
@@ -268,6 +268,35 @@ void createDataSetAndControlBlocks_should_create_ControlBlocks() {
268268
new ControlBlockTarget("AP_NAME", "IED_NAME1", "LD_INST11", "", "LLN0", "", ""));
269269
}
270270

271+
@Test
272+
void createDataSetAndControlBlocks_should_set_ExtRef_srcXXX_attributes() {
273+
// Given
274+
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-extref-create-dataset-and-controlblocks/scd_create_dataset_and_controlblocks_success.xml");
275+
// When
276+
SclReport sclReport = ExtRefService.createDataSetAndControlBlocks(scd);
277+
// Then
278+
assertThat(sclReport.getSclReportItems()).isEmpty();
279+
280+
// assert all ExtRef.srcPrefix srcLNClass srcLNInst are not set
281+
assertThat(streamAllExtRef(sclReport.getSclRootAdapter()))
282+
.extracting(TExtRef::getSrcPrefix, TExtRef::getSrcLNClass, TExtRef::getSrcLNInst)
283+
.containsOnly(Tuple.tuple(null, Collections.emptyList(), null));
284+
285+
// check some ExtRef
286+
assertThat(findExtRef(sclReport, "IED_NAME1", "LD_INST11", "test bay internal"))
287+
.extracting(TExtRef::getSrcCBName, TExtRef::getSrcLDInst)
288+
.containsExactly("CB_LD_INST21_GSI", "LD_INST21");
289+
assertThat(findExtRef(sclReport, "IED_NAME1", "LD_INST11", "test bay external"))
290+
.extracting(TExtRef::getSrcCBName, TExtRef::getSrcLDInst)
291+
.containsExactly("CB_LD_INST31_GSE", "LD_INST31");
292+
assertThat(findExtRef(sclReport, "IED_NAME1", "LD_INST11", "test ServiceType is SMV, no daName and DO contains ST and MX, but only ST is FCDA candidate"))
293+
.extracting(TExtRef::getSrcCBName, TExtRef::getSrcLDInst)
294+
.containsExactly("CB_LD_INST21_SVI", "LD_INST21");
295+
assertThat(findExtRef(sclReport, "IED_NAME1", "LD_INST11", "test ServiceType is Report_daReportMX_1"))
296+
.extracting(TExtRef::getSrcCBName, TExtRef::getSrcLDInst)
297+
.containsExactly("CB_LD_INST21_CYCI", "LD_INST21");
298+
}
299+
271300
@Test
272301
void createDataSetAndControlBlocks_when_targetIedName_is_provided_should_succeed() {
273302
// Given

0 commit comments

Comments
 (0)