Skip to content

Commit 2e44581

Browse files
authored
Merge pull request #264 from com-pas/feat/257-create-supervision-lns--lgos-lsvs-for-cb-gse-smv
feat(#257): manage (update and/or create) monitoring LNs LSVS and LGOS for Control Blocks GOOSE and SMV
2 parents fd98b51 + 6aa234e commit 2e44581

File tree

17 files changed

+1120
-200
lines changed

17 files changed

+1120
-200
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.apache.commons.lang3.StringUtils;
99
import org.lfenergy.compas.scl2007b4.model.SCL;
1010
import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader;
11+
import org.lfenergy.compas.scl2007b4.model.TExtRef;
1112
import org.lfenergy.compas.scl2007b4.model.TIED;
1213
import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
1314
import org.lfenergy.compas.sct.commons.dto.SclReport;
@@ -27,6 +28,7 @@
2728
import java.util.stream.Stream;
2829

2930
import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.*;
31+
import static org.lfenergy.compas.sct.commons.util.Utils.isExtRefFeedBySameControlBlock;
3032

3133
@UtilityClass
3234
public class ExtRefService {
@@ -226,4 +228,19 @@ private static Optional<SclReportItem> configureControlBlockNetwork(ControlBlock
226228
return controlBlockAdapter.configureNetwork(appIdIterator.nextLong(), macAddressIterator.next(), settings.vlanId(), settings.vlanPriority(),
227229
settings.minTime(), settings.maxTime());
228230
}
231+
232+
233+
/**
234+
* Remove ExtRef which are fed by same Control Block
235+
*
236+
* @return list ExtRefs without duplication
237+
*/
238+
public static List<TExtRef> filterDuplicatedExtRefs(List<TExtRef> tExtRefs) {
239+
List<TExtRef> filteredList = new ArrayList<>();
240+
tExtRefs.forEach(tExtRef -> {
241+
if (filteredList.stream().noneMatch(t -> isExtRefFeedBySameControlBlock(tExtRef, t)))
242+
filteredList.add(tExtRef);
243+
});
244+
return filteredList;
245+
}
229246
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public class SclService {
8080

8181
private static final String UNKNOWN_LDEVICE_S_IN_IED_S = "Unknown LDevice (%s) in IED (%s)";
8282
private static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info";
83+
private static final String IED_TEST_NAME = "IEDTEST";
8384

8485
private SclService() {
8586
throw new IllegalStateException("SclService class");
@@ -609,4 +610,20 @@ public static SclReport updateDoInRef(SCL scd) {
609610
.toList();
610611
return new SclReport(sclRootAdapter, sclReportItems);
611612
}
613+
614+
/**
615+
* Update and/or create Monitoring LNs (LSVS and LGOS) for bound GOOSE and SMV Control Blocks
616+
*
617+
* @param scd SCL file for which LNs (LSVS and LGOS) should be updated and/or created in each LDevice LDSUIED with matching ExtRef information
618+
* @return SclReport Object that contain SCL file and set of errors
619+
*/
620+
public static SclReport manageMonitoringLns(SCL scd) {
621+
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
622+
List<SclReportItem> sclReportItems = sclRootAdapter.streamIEDAdapters()
623+
.filter(iedAdapter -> !iedAdapter.getName().contains(IED_TEST_NAME))
624+
.map(IEDAdapter::manageMonitoringLns)
625+
.flatMap(List::stream)
626+
.toList();
627+
return new SclReport(sclRootAdapter, sclReportItems);
628+
}
612629
}

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

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import java.util.stream.Collectors;
1818
import java.util.stream.Stream;
1919

20+
import static org.lfenergy.compas.sct.commons.scl.ExtRefService.filterDuplicatedExtRefs;
21+
2022
/**
2123
* A representation of the model object
2224
* <em><b>{@link org.lfenergy.compas.scl2007b4.model.TAccessPoint AccessPoint}</b></em>.
@@ -35,7 +37,6 @@
3537
public class AccessPointAdapter extends SclElementAdapter<IEDAdapter, TAccessPoint> {
3638

3739
public static final long MAX_OCCURRENCE_NO_LIMIT_VALUE = -1L;
38-
private static final String CLIENT_IED_NAME = "The Client IED ";
3940

4041
/**
4142
* Constructor
@@ -219,7 +220,7 @@ public Optional<SclReportItem> checkLimitationForBoundIedFcdas(List<TExtRef> tEx
219220
* @param sclReportItems
220221
* @param tExtRefs
221222
*/
222-
record ExtRefAnalyzeRecord(List<SclReportItem> sclReportItems, List<TExtRef> tExtRefs) {
223+
public record ExtRefAnalyzeRecord(List<SclReportItem> sclReportItems, List<TExtRef> tExtRefs) {
223224
}
224225

225226
/**
@@ -229,21 +230,20 @@ record ExtRefAnalyzeRecord(List<SclReportItem> sclReportItems, List<TExtRef> tEx
229230
*/
230231
public ExtRefAnalyzeRecord getAllCoherentExtRefForAnalyze() {
231232
List<SclReportItem> sclReportItems = new ArrayList<>();
232-
List<TExtRef> tExtRefList = new ArrayList<>();
233-
streamLDeviceAdapters().map(lDeviceAdapter -> {
234-
List<TExtRef> extRefs = lDeviceAdapter.getLN0Adapter().getExtRefs().stream().filter(TExtRef::isSetSrcCBName).collect(Collectors.toCollection(ArrayList::new));
235-
sclReportItems.addAll(checkExtRefWithoutServiceType(extRefs, lDeviceAdapter.getLN0Adapter().getXPath()));
236-
extRefs.removeIf(tExtRef -> !tExtRef.isSetServiceType());
237-
return extRefs;
238-
}).flatMap(Collection::stream).forEach(tExtRef -> {
239-
if (tExtRefList.isEmpty())
240-
tExtRefList.add(tExtRef);
241-
else {
242-
if (tExtRefList.stream().noneMatch(t -> isExtRefFeedBySameControlBlock(tExtRef, t)))
243-
tExtRefList.add(tExtRef);
244-
}
245-
});
246-
return new ExtRefAnalyzeRecord(sclReportItems, tExtRefList);
233+
List<TExtRef> tExtRefList = streamLDeviceAdapters()
234+
.map(LDeviceAdapter::getLN0Adapter)
235+
.map(ln0Adapter -> {
236+
List<TExtRef> extRefs = new ArrayList<>();
237+
if (ln0Adapter.hasInputs()) {
238+
extRefs.addAll(ln0Adapter.getInputsAdapter().filterDuplicatedExtRefs()
239+
.stream().filter(TExtRef::isSetSrcCBName).collect(Collectors.toCollection(ArrayList::new)));
240+
sclReportItems.addAll(checkExtRefWithoutServiceType(extRefs, ln0Adapter.getXPath()));
241+
extRefs.removeIf(tExtRef -> !tExtRef.isSetServiceType());
242+
}
243+
return extRefs;
244+
}).flatMap(Collection::stream)
245+
.toList();
246+
return new ExtRefAnalyzeRecord(sclReportItems, filterDuplicatedExtRefs(tExtRefList));
247247
}
248248

249249
/**
@@ -262,25 +262,6 @@ private List<SclReportItem> checkExtRefWithoutServiceType(List<TExtRef> tExtRefs
262262
.toList();
263263
}
264264

265-
/**
266-
* Checks if two ExtRefs fed by same Control Block for SCL limits analyze
267-
* Nota : this equality is only for checking limitation check
268-
*
269-
* @param t1 extref to compare
270-
* @param t2 extref to compare
271-
* @return true if the two ExtRef are fed by same Control Block, otherwise false
272-
*/
273-
private static boolean isExtRefFeedBySameControlBlock(TExtRef t1, TExtRef t2) {
274-
String srcLNClass1 = (t1.isSetSrcLNClass()) ? t1.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value();
275-
String srcLNClass2 = (t2.isSetSrcLNClass()) ? t2.getSrcLNClass().get(0) : TLLN0Enum.LLN_0.value();
276-
return Utils.equalsOrBothBlank(t1.getIedName(), t2.getIedName())
277-
&& Utils.equalsOrBothBlank(t1.getSrcLDInst(), t2.getSrcLDInst())
278-
&& srcLNClass1.equals(srcLNClass2)
279-
&& Utils.equalsOrBothBlank(t1.getSrcLNInst(), t2.getSrcLNInst())
280-
&& Utils.equalsOrBothBlank(t1.getSrcPrefix(), t2.getSrcPrefix())
281-
&& t1.getServiceType().equals(t2.getServiceType());
282-
}
283-
284265
/**
285266
* Checks Control Blocks (Report, Goose, SMV) number limitation for bound IED
286267
*
@@ -300,7 +281,6 @@ public List<SclReportItem> checkLimitationForBoundIEDControls(List<TExtRef> tExt
300281
* Checks Control Block number limitation for bound IED
301282
*
302283
* @param tExtRefs list of ExtRefs referenced same ied
303-
* @param msg message to display hen error occured
304284
* @param servicesConfigEnum type of Control Block for which check is done
305285
* @return Optional of encountered error or empty
306286
*/

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

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515
import org.lfenergy.compas.sct.commons.scl.PrivateService;
1616
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
1717
import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
18+
import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum;
1819
import org.lfenergy.compas.sct.commons.util.ServicesConfigEnum;
1920
import org.lfenergy.compas.sct.commons.util.Utils;
2021

21-
import java.util.List;
22-
import java.util.Map;
23-
import java.util.Objects;
24-
import java.util.Optional;
22+
import java.util.*;
2523
import java.util.function.Function;
2624
import java.util.stream.Stream;
2725

@@ -62,6 +60,9 @@
6260
public class IEDAdapter extends SclElementAdapter<SclRootAdapter, TIED> {
6361

6462
private static final String MESSAGE_LDEVICE_INST_NOT_FOUND = "LDevice.inst '%s' not found in IED '%s'";
63+
private static final String DO_GOCBREF = "GoCBRef";
64+
private static final String DO_SVCBREF = "SvCBRef";
65+
private static final String LDSUIED_LDINST = "LDSUIED";
6566

6667
/**
6768
* Constructor
@@ -91,10 +92,10 @@ public IEDAdapter(SclRootAdapter parentAdapter, TIED currentElem) {
9192
public IEDAdapter(SclRootAdapter parentAdapter, String iedName) throws ScdException {
9293
super(parentAdapter);
9394
TIED ied = parentAdapter.getCurrentElem().getIED()
94-
.stream()
95-
.filter(tied -> tied.getName().equals(iedName))
96-
.findFirst()
97-
.orElseThrow(() -> new ScdException("Unknown IED name :" + iedName));
95+
.stream()
96+
.filter(tied -> tied.getName().equals(iedName))
97+
.findFirst()
98+
.orElseThrow(() -> new ScdException("Unknown IED name :" + iedName));
9899
setCurrentElem(ied);
99100
}
100101

@@ -326,47 +327,50 @@ public Optional<TCompasBay> getPrivateCompasBay() {
326327

327328
/**
328329
* Checks if Controls, DataSets and FCDAs of IED respect config limitation
330+
*
329331
* @return empty list if all IED respect limits, otherwise list of errors
330332
*/
331333
public List<SclReportItem> checkDataGroupCoherence() {
332334
return streamAccessPointAdapters()
333335
.flatMap(accessPointAdapter ->
334336
Stream.concat(
335-
accessPointAdapter.checkFCDALimitations().stream(),
336-
Stream.of(
337-
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.DATASET),
338-
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.REPORT),
339-
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.GSE),
340-
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.SMV))
341-
.flatMap(Optional::stream)
337+
accessPointAdapter.checkFCDALimitations().stream(),
338+
Stream.of(
339+
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.DATASET),
340+
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.REPORT),
341+
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.GSE),
342+
accessPointAdapter.checkControlsLimitation(ServicesConfigEnum.SMV))
343+
.flatMap(Optional::stream)
342344
)
343345
)
344346
.toList();
345347
}
346348

347349
/**
348350
* Checks if Controls and FCDAs of source IEDs respect config limitation
351+
*
349352
* @return empty list if all IED respect limits, otherwise list of errors
350353
*/
351354
public List<SclReportItem> checkBindingDataGroupCoherence() {
352-
return streamAccessPointAdapters()
355+
return streamAccessPointAdapters()
353356
.flatMap(accessPointAdapter -> {
354357
AccessPointAdapter.ExtRefAnalyzeRecord extRefAnalyzeRecord = accessPointAdapter.getAllCoherentExtRefForAnalyze();
355358
return Stream.of(
356-
extRefAnalyzeRecord.sclReportItems().stream(),
357-
accessPointAdapter.checkLimitationForBoundIedFcdas(extRefAnalyzeRecord.tExtRefs()).stream(),
358-
accessPointAdapter.checkLimitationForBoundIEDControls(extRefAnalyzeRecord.tExtRefs()).stream())
359-
.flatMap(Function.identity());
359+
extRefAnalyzeRecord.sclReportItems().stream(),
360+
accessPointAdapter.checkLimitationForBoundIedFcdas(extRefAnalyzeRecord.tExtRefs()).stream(),
361+
accessPointAdapter.checkLimitationForBoundIEDControls(extRefAnalyzeRecord.tExtRefs()).stream())
362+
.flatMap(Function.identity());
360363
}).toList();
361364
}
362365

363366
private Stream<AccessPointAdapter> streamAccessPointAdapters() {
364367
return currentElem.getAccessPoint().stream()
365-
.map(tAccessPoint -> new AccessPointAdapter(this, tAccessPoint));
368+
.map(tAccessPoint -> new AccessPointAdapter(this, tAccessPoint));
366369
}
367370

368371
/**
369372
* Get value of private type COMPAS-ICDHeader
373+
*
370374
* @return COMPAS-ICDHeader private value if present, else empty Optional
371375
*/
372376
public Optional<TCompasICDHeader> getCompasICDHeader() {
@@ -375,10 +379,40 @@ public Optional<TCompasICDHeader> getCompasICDHeader() {
375379

376380
/**
377381
* Get value of private type COMPAS-SystemVersion
382+
*
378383
* @return COMPAS-SystemVersion private value if present, else empty Optional
379384
*/
380385
public Optional<TCompasSystemVersion> getCompasSystemVersion() {
381386
return PrivateService.extractCompasPrivate(currentElem, TCompasSystemVersion.class);
382387
}
383388

389+
/**
390+
* Update and/or create Monitoring LNs (LSVS and LGOS) into LDSUIED for each bound ExtRef of each LDevice
391+
*
392+
* @return a list of SclReport Objects that contains errors
393+
*/
394+
public List<SclReportItem> manageMonitoringLns() {
395+
List<SclReportItem> sclReportItems = new ArrayList<>();
396+
findLDeviceAdapterByLdInst(LDSUIED_LDINST).ifPresent(lDeviceAdapter -> {
397+
lDeviceAdapter.manageMonitoringLns(retrieveAllExtRefForServiceType(TServiceType.GOOSE), DO_GOCBREF, MonitoringLnClassEnum.LGOS)
398+
.ifPresent(sclReportItems::add);
399+
lDeviceAdapter.manageMonitoringLns(retrieveAllExtRefForServiceType(TServiceType.SMV), DO_SVCBREF, MonitoringLnClassEnum.LSVS)
400+
.ifPresent(sclReportItems::add);
401+
});
402+
return sclReportItems;
403+
}
404+
405+
private List<TExtRef> retrieveAllExtRefForServiceType(TServiceType tServiceType) {
406+
return streamLDeviceAdapters()
407+
.map(LDeviceAdapter::getLN0Adapter)
408+
.filter(AbstractLNAdapter::hasInputs)
409+
.map(LN0Adapter::getInputsAdapter)
410+
.map(InputsAdapter::filterDuplicatedExtRefs)
411+
.flatMap(List::stream)
412+
.filter(tExtRef -> tExtRef.isSetServiceType() && tExtRef.isSetSrcCBName() &&
413+
tServiceType.equals(tExtRef.getServiceType()))
414+
.toList();
415+
}
416+
417+
384418
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate;
1212
import org.lfenergy.compas.sct.commons.dto.SclReportItem;
1313
import org.lfenergy.compas.sct.commons.exception.ScdException;
14+
import org.lfenergy.compas.sct.commons.scl.ExtRefService;
1415
import org.lfenergy.compas.sct.commons.scl.PrivateService;
1516
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
1617
import org.lfenergy.compas.sct.commons.scl.SclRootAdapter;
@@ -421,4 +422,13 @@ private SclRootAdapter getSclRootAdapter() {
421422
return getIedAdapter().getParentAdapter();
422423
}
423424

425+
/**
426+
* Remove ExtRef which are fed by same Control Block
427+
*
428+
* @return list ExtRefs without duplication
429+
*/
430+
public List<TExtRef> filterDuplicatedExtRefs() {
431+
return ExtRefService.filterDuplicatedExtRefs(getExtRefs());
432+
}
433+
424434
}

0 commit comments

Comments
 (0)