Skip to content

Commit a3f364b

Browse files
Merge pull request #419 from com-pas/develop
Release 0.2.28
2 parents 662b3da + 72617bc commit a3f364b

File tree

12 files changed

+343
-38
lines changed

12 files changed

+343
-38
lines changed

sct-commons/src/main/java/org/lfenergy/compas/sct/commons/ExtRefEditorService.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import lombok.RequiredArgsConstructor;
88
import org.lfenergy.compas.scl2007b4.model.*;
99
import org.lfenergy.compas.sct.commons.api.ExtRefEditor;
10+
import org.lfenergy.compas.sct.commons.api.LnEditor;
11+
import org.lfenergy.compas.sct.commons.domain.*;
1012
import org.lfenergy.compas.sct.commons.dto.*;
1113
import org.lfenergy.compas.sct.commons.exception.ScdException;
1214
import org.lfenergy.compas.sct.commons.model.epf.EPF;
@@ -46,6 +48,7 @@ public class ExtRefEditorService implements ExtRefEditor {
4648

4749
private final IedService iedService;
4850
private final LdeviceService ldeviceService;
51+
private final LnEditor lnEditor;
4952
private final ExtRefService extRefService;
5053
private final DataTypeTemplatesService dataTypeTemplatesService;
5154

@@ -323,6 +326,41 @@ public List<SclReportItem> manageBindingForLDEPF(SCL scd, EPF epf) {
323326
return sclReportItems;
324327
}
325328

329+
@Override
330+
public void epfPostProcessing(SCL scd) {
331+
iedService.getFilteredIeds(scd, ied -> !ied.getName().contains("TEST"))
332+
.forEach(tied -> ldeviceService.findLdevice(tied, tlDevice -> LDEVICE_LDEPF.equals(tlDevice.getInst()))
333+
.ifPresent(tlDevice -> tlDevice.getLN0().getDOI()
334+
.stream().filter(tdoi -> tdoi.getName().startsWith(INREF_PREFIX))
335+
.forEach(tdoi -> {
336+
DoLinkedToDaFilter doLinkedToSetSrcRef = new DoLinkedToDaFilter(tdoi.getName(), List.of(), SETSRCREF_DA_NAME, List.of());
337+
Optional<TDAI> setSrcRefDAI = lnEditor.getDOAndDAInstances(tlDevice.getLN0(), doLinkedToSetSrcRef);
338+
DoLinkedToDaFilter doLinkedPurPose = new DoLinkedToDaFilter(tdoi.getName(), List.of(), PURPOSE_DA_NAME, List.of());
339+
Optional<TDAI> purPoseDAI = lnEditor.getDOAndDAInstances(tlDevice.getLN0(), doLinkedPurPose);
340+
341+
boolean isSetSrcRefExistAndEmpty = setSrcRefDAI.isPresent()
342+
&& (!setSrcRefDAI.get().isSetVal()
343+
|| (setSrcRefDAI.get().isSetVal()
344+
&& setSrcRefDAI.get().getVal().getFirst().getValue().isEmpty()));
345+
boolean isPurposeExistAndMatchChannel = purPoseDAI.isPresent()
346+
&& purPoseDAI.get().isSetVal()
347+
&& (purPoseDAI.get().getVal().getFirst().getValue().startsWith("DYN_LDEPF_DIGITAL CHANNEL")
348+
|| purPoseDAI.get().getVal().getFirst().getValue().startsWith("DYN_LDEPF_ANALOG CHANNEL"));
349+
if(isSetSrcRefExistAndEmpty && isPurposeExistAndMatchChannel) {
350+
351+
DoLinkedToDa doLinkedToDa = new DoLinkedToDa();
352+
DataObject dataObject = new DataObject();
353+
dataObject.setDoName(tdoi.getName());
354+
doLinkedToDa.setDataObject(dataObject);
355+
DataAttribute dataAttribute = new DataAttribute();
356+
dataAttribute.setDaName(SETSRCREF_DA_NAME);
357+
dataAttribute.setDaiValues(List.of(new DaVal(null, tied.getName()+tlDevice.getInst()+"/LPHD0.Proxy")));
358+
doLinkedToDa.setDataAttribute(dataAttribute);
359+
lnEditor.updateOrCreateDOAndDAInstances(tlDevice.getLN0(), doLinkedToDa);
360+
}
361+
})));
362+
}
363+
326364
private List<SclReportItem> validateIed(SclRootAdapter sclRootAdapter) {
327365
List<SclReportItem> iedErrors = new ArrayList<>(checkIedCompasIcdHeaderAttributes(sclRootAdapter));
328366
iedErrors.addAll(checkIedUnityOfIcdSystemVersionUuid(sclRootAdapter));

sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/ExtRefEditor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ public interface ExtRefEditor {
6363
*/
6464
List<SclReportItem> manageBindingForLDEPF(SCL scd, EPF epf);
6565

66+
/**
67+
* Pointing an unused channel to an existing object LPHD0.Proxy of the concerned IED.
68+
* An unused channel is characterized by the value DAI name ="setSrcRef"/Val (should be empty) in InRef**
69+
* that have a purpose beginning by DYN_LDEPF_DIGITAL CHANNEL or DYN_LDEPF_ANALOG CHANNEL
70+
* @param scd SCL
71+
*/
72+
void epfPostProcessing(SCL scd);
73+
6674
/**
6775
* Debinding of Private CompasFlows and ExtRef signals based on voltageLevel
6876
*

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class LDeviceAdapter extends SclElementAdapter<IEDAdapter, TLDevice> {
6666
private static final long INTG_PD_VALUE_FOR_FC_MX = 2000L;
6767

6868
private static final String DA_SETSRCREF = "setSrcRef";
69+
private static final String CYC_REPORT_TYPE = "CYC";
6970

7071
/**
7172
* Constructor
@@ -94,19 +95,19 @@ public void createHmiReportControlBlocks(PO po) {
9495
findLnAdapter(tfcdaFilter.getLnClass(), tfcdaFilter.getLnInst(), tfcdaFilter.getPrefix()).filter(lnAdapter -> lnAdapter.getDaiModStValValue().map(ActiveStatus::fromValue).map(ActiveStatus.ON::equals).orElse(true)))
9596
.map(sourceLn -> sourceLn.getDAI(new DataAttributeRef(toFCDA(tfcdaFilter)), false))
9697
.filter(das -> das.stream().anyMatch(da -> TFCEnum.fromValue(tfcdaFilter.getFc().value()) == da.getFc())) // getDAI does not filter on DA.
97-
.ifPresent(dataAttributeRefs -> createHmiReportCB(ln0, toFCDA(tfcdaFilter))));
98+
.ifPresent(dataAttributeRefs -> createHmiReportCB(ln0, tfcdaFilter)));
9899
}
99100

100-
private void createHmiReportCB(LN0Adapter ln0, TFCDA fcda) {
101-
boolean isFcMx = fcda.getFc() == TFCEnum.MX;
102-
String dataSetSuffix = getInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + (isFcMx ? "CYPO" : "DQPO");
101+
private void createHmiReportCB(LN0Adapter ln0, TFCDAFilter tfcdaFilter) {
102+
TFCDA fcda = toFCDA(tfcdaFilter);
103+
String dataSetSuffix = getInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + tfcdaFilter.getReportType().substring(0, 2) + "PO";
103104
String dataSetName = DATASET_NAME_PREFIX + dataSetSuffix;
104105
DataSetAdapter dataSet = ln0.createDataSetIfNotExists(dataSetName, ControlBlockEnum.REPORT);
105-
dataSet.createFCDAIfNotExists(fcda.getLdInst(), fcda.getPrefix(), fcda.getLnClass().get(0), fcda.getLnInst(), fcda.getDoName(), fcda.getDaName(), fcda.getFc());
106+
dataSet.createFCDAIfNotExists(fcda.getLdInst(), fcda.getPrefix(), fcda.getLnClass().getFirst(), fcda.getLnInst(), fcda.getDoName(), fcda.getDaName(), fcda.getFc());
106107
String cbName = CONTROLBLOCK_NAME_PREFIX + dataSetSuffix;
107108
String cbId = ln0.generateControlBlockId(getLdName(), cbName);
108109
ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists(cbName, cbId, dataSetName, ControlBlockEnum.REPORT);
109-
if (isFcMx) {
110+
if (tfcdaFilter.getReportType().equals(CYC_REPORT_TYPE)) {
110111
TReportControl tReportControl = (TReportControl) controlBlockAdapter.getCurrentElem();
111112
tReportControl.setIntgPd(INTG_PD_VALUE_FOR_FC_MX);
112113
tReportControl.getTrgOps().setDchg(false);
@@ -478,7 +479,7 @@ private void updateNewCreatedLnDaiValue(TLN tln, TExtRef tExtRef, String lnInst,
478479
private String createVal(TExtRef tExtRef) {
479480
String sourceLdName = getParentAdapter().getParentAdapter().getIEDAdapterByName(tExtRef.getIedName())
480481
.getLDeviceAdapterByLdInst(tExtRef.getSrcLDInst()).getLdName();
481-
String lnClass = !tExtRef.isSetSrcLNClass() ? TLLN0Enum.LLN_0.value() : tExtRef.getSrcLNClass().get(0);
482+
String lnClass = !tExtRef.isSetSrcLNClass() ? TLLN0Enum.LLN_0.value() : tExtRef.getSrcLNClass().getFirst();
482483
return sourceLdName + "/" + lnClass + "." + tExtRef.getSrcCBName();
483484
}
484485

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

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@
88
import org.apache.commons.lang3.tuple.Pair;
99
import org.lfenergy.compas.scl2007b4.model.*;
1010
import org.lfenergy.compas.sct.commons.dto.*;
11-
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceActivation;
1211
import org.lfenergy.compas.sct.commons.scl.ObjectReference;
1312
import org.lfenergy.compas.sct.commons.scl.ied.InputsAdapter;
13+
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceActivation;
1414
import org.lfenergy.compas.sct.commons.scl.ldevice.LDeviceAdapter;
1515
import org.lfenergy.compas.sct.commons.util.PrivateUtils;
1616

1717
import java.util.List;
1818
import java.util.Optional;
1919
import java.util.Set;
20+
import java.util.regex.Pattern;
2021
import java.util.stream.Collectors;
2122

22-
import static org.lfenergy.compas.sct.commons.util.CommonConstants.BEHAVIOUR_DO_NAME;
23-
import static org.lfenergy.compas.sct.commons.util.CommonConstants.STVAL_DA_NAME;
23+
import static org.lfenergy.compas.sct.commons.util.CommonConstants.*;
2424

2525
/**
2626
* A representation of the model object
@@ -47,9 +47,6 @@
4747
* <li>{@link LN0Adapter#getDAI <em>Returns the value of the <b>DataAttributeRef </b> containment reference By filter</em>}</li>
4848
* <li>{@link LN0Adapter#getDAIValues(DataAttributeRef) <em>Returns <b>DAI (sGroup, value) </b> containment reference list By <b>DataAttributeRef </b> filter</em>}</li>
4949
*
50-
* <li>{@link LN0Adapter#getDataSetByName(String) <em>Returns the value of the <b>TDataSet </b>object reference By the value of the <b>name </b>attribute </em>}</li>
51-
*
52-
* <li>{@link LN0Adapter#getControlBlocks(List, TServiceType) <em>Returns the value of the <b>ControlBlock </b>containment reference list that match <b>datSet </b> value of given <b>TDataSet</b> </em>}</li>
5350
* <li>{@link LN0Adapter#addPrivate <em>Add <b>TPrivate </b>under this object</em>}</li>
5451
* <li>{@link LN0Adapter#removeAllControlBlocksAndDatasets() <em>Remove all <b>ControlBlock</b></em>}</li>
5552
* </ul>
@@ -73,8 +70,7 @@ public class LN0Adapter extends AbstractLNAdapter<LN0> {
7370

7471
public static final DoTypeName BEHAVIOUR_DO_TYPE_NAME = new DoTypeName(BEHAVIOUR_DO_NAME);
7572
public static final DaTypeName BEHAVIOUR_DA_TYPE_NAME = getDaTypeNameForBeh();
76-
private static final String DAI_NAME_PURPOSE = "purpose";
77-
private static final String INREF_PREFIX = "InRef";
73+
private static final Pattern LDEFP_DIGITAL_CHANNEL_PATTERN = Pattern.compile("DYN_LDEPF_DIGITAL CHANNEL \\d+_\\d+_BOOLEAN");
7874

7975
/**
8076
* Constructor
@@ -188,7 +184,7 @@ public Optional<SclReportItem> updateLDeviceStatus(List<Pair<String, String>> ie
188184
if (daiBehList.isEmpty()) {
189185
return Optional.of(buildFatalReportItem("The LDevice doesn't have a DO @name='Beh' OR its associated DA@fc='ST' AND DA@name='stVal'"));
190186
}
191-
Set<String> enumValues = getEnumValues(daiBehList.get(0).getDaName().getType());
187+
Set<String> enumValues = getEnumValues(daiBehList.getFirst().getDaName().getType());
192188
Optional<TCompasLDevice> optionalTCompasLDevice = PrivateUtils.extractCompasPrivate(getParentAdapter().getCurrentElem(), TCompasLDevice.class);
193189
if (optionalTCompasLDevice.isEmpty()) {
194190
return Optional.of(buildFatalReportItem("The LDevice doesn't have a Private compas:LDevice."));
@@ -234,16 +230,26 @@ public List<SclReportItem> updateDoInRef() {
234230
return getDOIAdapters().stream()
235231
.filter(doiAdapter -> doiAdapter.getCurrentElem().isSetName()
236232
&& doiAdapter.getCurrentElem().getName().startsWith(INREF_PREFIX)
237-
&& doiAdapter.findDataAdapterByName(DAI_NAME_PURPOSE).isPresent())
238-
.map(doiAdapter -> doiAdapter.getDataAdapterByName(DAI_NAME_PURPOSE).getCurrentElem().getVal().stream()
233+
&& doiAdapter.findDataAdapterByName(PURPOSE_DA_NAME).isPresent())
234+
.map(doiAdapter -> doiAdapter.getDataAdapterByName(PURPOSE_DA_NAME).getCurrentElem().getVal().stream()
239235
.findFirst()
240-
.map(tVal -> doiAdapter.updateDaiFromExtRef(getBoundExtRefsByDesc(tVal.getValue())))
236+
.map(tVal -> doiAdapter.updateDaiFromExtRef(getExtRefsBoundToInRef(tVal.getValue())))
241237
.orElse(List.of(SclReportItem.warning(getXPath(), "The DOI %s can't be bound with an ExtRef".formatted(getXPath()))))
242238
)
243239
.flatMap(List::stream)
244240
.collect(Collectors.toList());
245241
}
246242

243+
private List<TExtRef> getExtRefsBoundToInRef(String desc) {
244+
List<TExtRef> boundExtRefs = getBoundExtRefsByDesc(desc);
245+
// Special case for LDEPF DIGITAL CHANNEL of type BOOLEAN RSR-1048
246+
if (boundExtRefs.isEmpty() && LDEFP_DIGITAL_CHANNEL_PATTERN.matcher(desc).matches()) {
247+
String descWithoutType = desc.substring(0, desc.lastIndexOf("_"));
248+
return getBoundExtRefsByDesc(descWithoutType);
249+
}
250+
return boundExtRefs;
251+
}
252+
247253
private List<TExtRef> getBoundExtRefsByDesc(String desc) {
248254
return getExtRefs().stream()
249255
.filter(tExtRef -> tExtRef.isSetIedName() && tExtRef.isSetLdInst() && tExtRef.isSetLnClass() && tExtRef.isSetDoName() &&

sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ public final class CommonConstants {
3636
public static final String SETSRCCB_DA_NAME = "setSrcCB";
3737
public static final String SETTSTREF_DA_NAME = "setTstRef";
3838
public static final String SETTSTCB_DA_NAME = "setTstCB";
39+
public static final String PURPOSE_DA_NAME = "purpose";
3940
public static final String Q_DA_NAME = "q";
4041
public static final String IED_TEST_NAME = "IEDTEST";
42+
public static final String INREF_PREFIX = "InRef";
4143

4244
/**
4345
* Private Controlller, should not be instanced

sct-commons/src/main/resources/xsd/CB_REPORT_SUPERVISION_Config_file.xsd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ SPDX-License-Identifier: Apache-2.0
6060
<xs:attribute name="lnInst" type="xs:string" use="required"/>
6161
<xs:attribute name="doName" type="xs:string" use="required"/>
6262
<xs:attribute name="fc" type="tfc" use="required"/>
63+
<xs:attribute name="reportType" type="xs:string" use="required"/>
6364
</xs:complexType>
6465

6566
<xs:simpleType name="tfc">
@@ -69,4 +70,4 @@ SPDX-License-Identifier: Apache-2.0
6970
</xs:restriction>
7071
</xs:simpleType>
7172

72-
</xs:schema>
73+
</xs:schema>

sct-commons/src/test/java/org/lfenergy/compas/sct/commons/ExtRefEditorServiceTest.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.lfenergy.compas.sct.commons;
66

77
import org.assertj.core.api.Assertions;
8+
import org.assertj.core.api.SoftAssertions;
89
import org.assertj.core.groups.Tuple;
910
import org.junit.jupiter.api.BeforeEach;
1011
import org.junit.jupiter.api.Tag;
@@ -39,7 +40,7 @@ class ExtRefEditorServiceTest {
3940

4041
@BeforeEach
4142
void init() {
42-
extRefEditorService = new ExtRefEditorService(new IedService(), new LdeviceService(), new ExtRefService(), new DataTypeTemplatesService());
43+
extRefEditorService = new ExtRefEditorService(new IedService(), new LdeviceService(), new LnService(), new ExtRefService(), new DataTypeTemplatesService());
4344
}
4445

4546
@Test
@@ -955,4 +956,44 @@ void updateIedNameBasedOnLnode_when_no_Compas_ICD_Header_should_return_an_error(
955956
.containsExactly(Tuple.tuple(true,
956957
"The substation LNode with following attributes : IedName:IED_NAME2 / LdInst:LD_INST21 / LnClass:ANCR / LnInst:1 does not contain the needed (COMPAS - ICDHeader) private"));
957958
}
959+
960+
@Test
961+
void epfPostProcessing_when_exist_unused_channel_should_update_setSrcRef() {
962+
// Given
963+
SCL scd = SclTestMarshaller.getSCLFromFile("/scd-ldepf/scd_ldepf_postProcessing.xml");
964+
// When
965+
extRefEditorService.epfPostProcessing(scd);
966+
// Then
967+
SoftAssertions softly = new SoftAssertions();
968+
969+
Optional<TDAI> setSrcRefInInRef1 = findDai(scd, "IED_NAME1", "LDEPF", "InRef1", "setSrcRef");
970+
Optional<TDAI> purposeInInRef1 = findDai(scd, "IED_NAME1", "LDEPF", "InRef1", "purpose");
971+
assertThat(purposeInInRef1).isPresent();
972+
softly.assertThat(purposeInInRef1.get().getVal().getFirst().getValue()).doesNotStartWith("DYN_LDEPF_DIGITAL CHANNEL");
973+
softly.assertThat(purposeInInRef1.get().getVal().getFirst().getValue()).doesNotStartWith("DYN_LDEPF_ANALOG CHANNEL");
974+
assertThat(setSrcRefInInRef1).isPresent();
975+
softly.assertThat(setSrcRefInInRef1.get().isSetVal()).isFalse();
976+
977+
Optional<TDAI> setSrcRefInInRef2 = findDai(scd, "IED_NAME1", "LDEPF", "InRef2", "setSrcRef");
978+
Optional<TDAI> purposeInInRef2 = findDai(scd, "IED_NAME1", "LDEPF", "InRef2", "purpose");
979+
assertThat(purposeInInRef2).isPresent();
980+
softly.assertThat(purposeInInRef2.get().getVal().getFirst().getValue()).startsWith("DYN_LDEPF_DIGITAL CHANNEL");
981+
assertThat(setSrcRefInInRef2).isPresent();
982+
softly.assertThat(setSrcRefInInRef2.get().getVal().getFirst().getValue()).isEqualTo("IED_NAME1LDEPF/LPHD0.Proxy");
983+
984+
Optional<TDAI> setSrcRefInInRef3 = findDai(scd, "IED_NAME1", "LDEPF", "InRef3", "setSrcRef");
985+
Optional<TDAI> purposeInInRef3 = findDai(scd, "IED_NAME1", "LDEPF", "InRef3", "purpose");
986+
assertThat(purposeInInRef3).isPresent();
987+
softly.assertThat(purposeInInRef3.get().getVal().getFirst().getValue()).startsWith("DYN_LDEPF_DIGITAL CHANNEL");
988+
assertThat(setSrcRefInInRef3).isPresent();
989+
softly.assertThat(setSrcRefInInRef3.get().getVal().getFirst().getValue()).isEqualTo("IED_NAME1LDEPF/LPHD0.Proxy");
990+
991+
Optional<TDAI> setSrcRefInInRef4 = findDai(scd, "IED_NAME1", "LDEPF", "InRef4", "setSrcRef");
992+
Optional<TDAI> purposeInInRef4 = findDai(scd, "IED_NAME1", "LDEPF", "InRef4", "purpose");
993+
assertThat(purposeInInRef4).isPresent();
994+
softly.assertThat(purposeInInRef4.get().getVal().getFirst().getValue()).startsWith("DYN_LDEPF_ANALOG CHANNEL");
995+
assertThat(setSrcRefInInRef4).isPresent();
996+
softly.assertThat(setSrcRefInInRef4.get().getVal().getFirst().getValue()).isEqualTo("IED_NAME1LDEPF/LPHD0.Proxy");
997+
softly.assertAll();
998+
}
958999
}

0 commit comments

Comments
 (0)