From ee094ff90548cd1dc2f13952715d6680c132103f Mon Sep 17 00:00:00 2001 From: Samir Romdhani Date: Fri, 20 Sep 2024 17:49:13 +0200 Subject: [PATCH 1/3] fix : add synchronized Signed-off-by: Samir Romdhani --- .../compas/sct/commons/util/Utils.java | 12 +++++----- .../compas/sct/commons/util/UtilsTest.java | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java index 430e830ec..6515ac110 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java @@ -31,7 +31,6 @@ public final class Utils { private static final Pattern MAC_ADDRESS_PATTERN = Pattern.compile("[0-9A-F]{2}([-:][0-9A-F]{2}){5}", Pattern.CASE_INSENSITIVE); private static JAXBContext jaxbContext = null; - private static Unmarshaller unmarshaller = null; /** * Private Constructor, should not be instanced @@ -149,7 +148,7 @@ public static String xpathAttributeFilter(String name, Collection value) * @param s1 first string * @param s2 seconde string * @return true if strings are equals or both blank, false otherwise - * @see org.apache.commons.lang3.StringUtils#isBlank(CharSequence) + * @see StringUtils#isBlank(CharSequence) */ public static boolean equalsOrBothBlank(String s1, String s2) { return Objects.equals(s1, s2) @@ -167,9 +166,9 @@ public static boolean equalsOrBothBlank(String s1, String s2) { * @param s2 second String to compare * @return when s1 and s2 are not blank, same result as {@link String#compare(CharSequence, CharSequence)}, * zero when s1 and s2 are both blanks, negative integer when s1 is blank and s2 is not, positive integer when s1 is not blank but s2 is. - * @see java.util.Comparator#compare(Object, Object) - * @see org.apache.commons.lang3.StringUtils#isBlank(CharSequence) - * @see java.util.Comparator#nullsFirst(Comparator) + * @see Comparator#compare(Object, Object) + * @see StringUtils#isBlank(CharSequence) + * @see Comparator#nullsFirst(Comparator) */ public static int blanksFirstComparator(String s1, String s2) { if (StringUtils.isBlank(s1)){ @@ -314,11 +313,12 @@ public static String toHex(long number, int length) { * @return copy of the object */ public static T copySclElement(T object, Class clazz) { + Unmarshaller unmarshaller; try { if (jaxbContext == null) { jaxbContext = JAXBContext.newInstance("org.lfenergy.compas.scl2007b4.model"); - unmarshaller = jaxbContext.createUnmarshaller(); } + unmarshaller = jaxbContext.createUnmarshaller(); JAXBElement contentObject = new JAXBElement<>(new QName(clazz.getSimpleName()), clazz, object); JAXBSource source = new JAXBSource(jaxbContext, contentObject); return unmarshaller.unmarshal(source, clazz).getValue(); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java index 71512ec86..055f11978 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java @@ -18,6 +18,7 @@ import org.lfenergy.compas.sct.commons.exception.ScdException; import java.util.*; +import java.util.concurrent.*; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.*; @@ -482,6 +483,29 @@ void copySclElement_should_throwException() { .hasMessage("org.lfenergy.compas.sct.commons.dto.FCDAInfo is not known to this context"); } + @Test + void copySclElement_should_succeed_when_syncRead() throws ExecutionException, InterruptedException { + // Given + TLN tln = new TLN(); + tln.setLnType("T1"); + tln.getLnClass().add(TLLN0Enum.LLN_0.value()); + ExecutorService service = Executors.newFixedThreadPool(2); + Callable copySclElementTlnCallable = () -> copySclElement(tln, TLN.class); + // When + List> result = service.invokeAll(List.of(copySclElementTlnCallable, copySclElementTlnCallable)); + service.shutdown(); + TLN[] tlns = new TLN[]{result.getFirst().get(), result.getLast().get()}; + // Then + assertThat(tlns).hasSize(2); + assertThat(tlns[0]) + .isNotSameAs(tlns[1]) + .isNotSameAs(tln); + assertThat(tlns[0]) + .usingRecursiveComparison() + .isEqualTo(tlns[1]) + .isEqualTo(tln); + } + @Test void extractFromP_should_return_value_for_given_type(){ // Given From 54cf229c6877449b040ffe7f35133c3acdaee5b6 Mon Sep 17 00:00:00 2001 From: Samir Romdhani Date: Tue, 1 Oct 2024 13:38:38 +0200 Subject: [PATCH 2/3] feat: remove hmi service Signed-off-by: Samir Romdhani --- sct-commons/pom.xml | 19 -- .../compas/sct/commons/HmiService.java | 23 -- .../compas/sct/commons/api/HmiEditor.java | 24 -- .../commons/scl/ldevice/LDeviceAdapter.java | 57 ---- .../xsd/CB_REPORT_SUPERVISION_Config_file.xsd | 73 ------ .../compas/sct/commons/HmiServiceTest.java | 248 ------------------ ...eate_dataset_and_controlblocks_for_hmi.xml | 76 ------ 7 files changed, 520 deletions(-) delete mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/HmiService.java delete mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/HmiEditor.java delete mode 100644 sct-commons/src/main/resources/xsd/CB_REPORT_SUPERVISION_Config_file.xsd delete mode 100644 sct-commons/src/test/java/org/lfenergy/compas/sct/commons/HmiServiceTest.java delete mode 100644 sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml diff --git a/sct-commons/pom.xml b/sct-commons/pom.xml index a442ebc2c..afd3a44d7 100644 --- a/sct-commons/pom.xml +++ b/sct-commons/pom.xml @@ -197,25 +197,6 @@ false - - cb_po - - xjc - - - - - ${project.basedir}/src/main/resources/xsd/CB_REPORT_SUPERVISION_Config_file.xsd - - - - ${project.basedir}/src/main/resources/binding_configuration.xjb - - org.lfenergy.compas.sct.commons.model.cb_po - true - false - - cbcom diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/HmiService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/HmiService.java deleted file mode 100644 index 8969e7ad3..000000000 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/HmiService.java +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: 2023 RTE FRANCE -// -// SPDX-License-Identifier: Apache-2.0 - -package org.lfenergy.compas.sct.commons; - -import org.lfenergy.compas.scl2007b4.model.SCL; -import org.lfenergy.compas.sct.commons.api.HmiEditor; -import org.lfenergy.compas.sct.commons.model.cb_po.PO; -import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter; - -public class HmiService implements HmiEditor { - - @Override - public void createAllHmiReportControlBlocks(SCL scd, PO po) { - SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); - sclRootAdapter.streamIEDAdapters() - .flatMap(IEDAdapter::streamLDeviceAdapters) - .forEach(lDeviceAdapter -> lDeviceAdapter.createHmiReportControlBlocks(po)); - } - -} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/HmiEditor.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/HmiEditor.java deleted file mode 100644 index d90a55626..000000000 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/api/HmiEditor.java +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: 2023 RTE FRANCE -// -// SPDX-License-Identifier: Apache-2.0 - -package org.lfenergy.compas.sct.commons.api; - -import org.lfenergy.compas.scl2007b4.model.SCL; -import org.lfenergy.compas.scl2007b4.model.TReportControl; -import org.lfenergy.compas.sct.commons.model.cb_po.PO; - -/** - * Service class that will be used to manage elements related to the HMI {@link TReportControl Report Control Blocks}. - * - * @see Issue !258 - */ -public interface HmiEditor { - - /** - * Create the DataSet and ReportControl Blocks for the HMI with the given FCDAs. - * - * @param po object containing list of FCDA for which we must create the DataSet and ReportControl Blocks - */ - void createAllHmiReportControlBlocks(SCL scd, PO po); -} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ldevice/LDeviceAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ldevice/LDeviceAdapter.java index b12be812f..d606ec041 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ldevice/LDeviceAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ldevice/LDeviceAdapter.java @@ -10,24 +10,18 @@ import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.dto.*; import org.lfenergy.compas.sct.commons.exception.ScdException; -import org.lfenergy.compas.sct.commons.model.cb_po.PO; -import org.lfenergy.compas.sct.commons.model.cb_po.TFCDAFilter; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.DataSetAdapter; import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter; import org.lfenergy.compas.sct.commons.scl.ln.AbstractLNAdapter; import org.lfenergy.compas.sct.commons.scl.ln.LN0Adapter; import org.lfenergy.compas.sct.commons.scl.ln.LNAdapter; -import org.lfenergy.compas.sct.commons.util.ActiveStatus; import org.lfenergy.compas.sct.commons.util.ControlBlockEnum; import org.lfenergy.compas.sct.commons.util.MonitoringLnClassEnum; import org.lfenergy.compas.sct.commons.util.Utils; import java.util.*; -import static org.lfenergy.compas.sct.commons.util.CommonConstants.*; import static org.lfenergy.compas.sct.commons.util.Utils.copySclElement; /** @@ -63,10 +57,7 @@ @Slf4j public class LDeviceAdapter extends SclElementAdapter { - private static final long INTG_PD_VALUE_FOR_FC_MX = 2000L; - private static final String DA_SETSRCREF = "setSrcRef"; - private static final String CYC_REPORT_TYPE = "CYC"; /** * Constructor @@ -78,43 +69,6 @@ public LDeviceAdapter(IEDAdapter parentAdapter, TLDevice currentElem) { super(parentAdapter, currentElem); } - /** - * Create DataSet and ReportControl Blocks for the HMI with the given FCDAs. - * DataSet and ReportControl are created in LN0, even if FCDA refers to another LN. - * - * @param po object containing list of FCDA for which we must create the DataSet and ReportControl - */ - public void createHmiReportControlBlocks(PO po) { - LN0Adapter ln0 = getLN0Adapter(); - if (!ln0.getDaiModStValValue().map(ActiveStatus::fromValue).map(ActiveStatus.ON::equals).orElse(false)) return; - po.getFCDAs().getFCDA().stream() - .filter(tfcdaFilter -> getInst().equals(tfcdaFilter.getLdInst()) && tfcdaFilter.isSetLnClass()) - .forEach(tfcdaFilter -> (tfcdaFilter.getLnClass().equals(TLLN0Enum.LLN_0.value()) ? - Optional.of(ln0) // ln0 Mod stVal "ON" has already been checked, no need to check it again - : - findLnAdapter(tfcdaFilter.getLnClass(), tfcdaFilter.getLnInst(), tfcdaFilter.getPrefix()).filter(lnAdapter -> lnAdapter.getDaiModStValValue().map(ActiveStatus::fromValue).map(ActiveStatus.ON::equals).orElse(true))) - .map(sourceLn -> sourceLn.getDAI(new DataAttributeRef(toFCDA(tfcdaFilter)), false)) - .filter(das -> das.stream().anyMatch(da -> TFCEnum.fromValue(tfcdaFilter.getFc().value()) == da.getFc())) // getDAI does not filter on DA. - .ifPresent(dataAttributeRefs -> createHmiReportCB(ln0, tfcdaFilter))); - } - - private void createHmiReportCB(LN0Adapter ln0, TFCDAFilter tfcdaFilter) { - TFCDA fcda = toFCDA(tfcdaFilter); - String dataSetSuffix = getInst().toUpperCase(Locale.ENGLISH) + ATTRIBUTE_VALUE_SEPARATOR + tfcdaFilter.getReportType().substring(0, 2) + "PO"; - String dataSetName = DATASET_NAME_PREFIX + dataSetSuffix; - DataSetAdapter dataSet = ln0.createDataSetIfNotExists(dataSetName, ControlBlockEnum.REPORT); - dataSet.createFCDAIfNotExists(fcda.getLdInst(), fcda.getPrefix(), fcda.getLnClass().getFirst(), fcda.getLnInst(), fcda.getDoName(), fcda.getDaName(), fcda.getFc()); - String cbName = CONTROLBLOCK_NAME_PREFIX + dataSetSuffix; - String cbId = ln0.generateControlBlockId(getLdName(), cbName); - ControlBlockAdapter controlBlockAdapter = ln0.createControlBlockIfNotExists(cbName, cbId, dataSetName, ControlBlockEnum.REPORT); - if (tfcdaFilter.getReportType().equals(CYC_REPORT_TYPE)) { - TReportControl tReportControl = (TReportControl) controlBlockAdapter.getCurrentElem(); - tReportControl.setIntgPd(INTG_PD_VALUE_FOR_FC_MX); - tReportControl.getTrgOps().setDchg(false); - tReportControl.getTrgOps().setQchg(false); - } - } - /** * Check if node is child of the reference node * @@ -483,15 +437,4 @@ private String createVal(TExtRef tExtRef) { return sourceLdName + "/" + lnClass + "." + tExtRef.getSrcCBName(); } - private TFCDA toFCDA(TFCDAFilter tfcdaFilter) { - TFCDA tfcda = new TFCDA(); - tfcda.setLdInst(tfcdaFilter.getLdInst()); - tfcda.getLnClass().add(tfcdaFilter.getLnClass()); - tfcda.setPrefix(tfcdaFilter.getPrefix()); - tfcda.setLnInst(tfcdaFilter.getLnInst()); - tfcda.setDoName(tfcdaFilter.getDoName()); - tfcda.setFc(TFCEnum.fromValue(tfcdaFilter.getFc().value())); - return tfcda; - } - } diff --git a/sct-commons/src/main/resources/xsd/CB_REPORT_SUPERVISION_Config_file.xsd b/sct-commons/src/main/resources/xsd/CB_REPORT_SUPERVISION_Config_file.xsd deleted file mode 100644 index 307fc0f88..000000000 --- a/sct-commons/src/main/resources/xsd/CB_REPORT_SUPERVISION_Config_file.xsd +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/HmiServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/HmiServiceTest.java deleted file mode 100644 index 500065cc4..000000000 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/HmiServiceTest.java +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-FileCopyrightText: 2023 RTE FRANCE -// -// SPDX-License-Identifier: Apache-2.0 - -package org.lfenergy.compas.sct.commons; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.lfenergy.compas.scl2007b4.model.*; -import org.lfenergy.compas.sct.commons.model.cb_po.FCDAs; -import org.lfenergy.compas.sct.commons.model.cb_po.PO; -import org.lfenergy.compas.sct.commons.model.cb_po.TFCDAFilter; -import org.lfenergy.compas.sct.commons.model.cb_po.Tfc; -import org.lfenergy.compas.sct.commons.scl.ied.DataSetAdapter; -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.SclTestMarshaller; -import org.lfenergy.compas.sct.commons.util.ActiveStatus; -import org.lfenergy.compas.sct.commons.util.CommonConstants; -import org.mockito.InjectMocks; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.lfenergy.compas.sct.commons.testhelpers.SclHelper.*; - -@ExtendWith(MockitoExtension.class) -class HmiServiceTest { - - private static final String DQC_REPORT_TYPE = "DQC"; - private static final String CYC_REPORT_TYPE = "CYC"; - @InjectMocks - HmiService hmiService; - - private final PO po = new PO(); - - @BeforeEach - void setUp() { - FCDAs fcdAs = new FCDAs(); - po.setFCDAs(fcdAs); - } - - @Test - void createAllIhmReportControlBlocks_with_fc_ST_should_create_dataset_and_controlblock() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "ANCR", "1", null, "DoName1", Tfc.ST, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - // Check DataSet is created - DataSetAdapter dataSet = findDataSet(scd, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); - assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() - .usingRecursiveComparison().isEqualTo(toFCDA(tfcdaFilter)); - // Check ControlBlock is created - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); - TReportControl reportControl = findControlBlock(scd, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); - assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, - TControlWithTriggerOpt::getIntgPd) - .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); - assertThat(reportControl.getTrgOps()) - .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) - .containsExactly(true, true, false, true, true); - assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); - assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); - } - - @Test - void createAllIhmReportControlBlocks_with_fc_MX_should_create_dataset_and_controlblock() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "PVOC", "1", null, "DoName2", Tfc.MX, CYC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - // Check DataSet is created - DataSetAdapter dataSet = findDataSet(scd, "IedName1", "LdInst11", "DS_LDINST11_CYPO"); - assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() - .usingRecursiveComparison().isEqualTo(toFCDA(tfcdaFilter)); - // Check ControlBlock is created - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); - - TReportControl reportControl = findControlBlock(scd, "IedName1", "LdInst11", "CB_LDINST11_CYPO", TReportControl.class); - assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, - TControlWithTriggerOpt::getIntgPd) - .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_CYPO", "DS_LDINST11_CYPO", 1L, true, 0L, true, 2000L); - assertThat(reportControl.getTrgOps()) - .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) - .containsExactly(false, false, false, true, true); - assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); - assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); - } - - @Test - void createAllIhmReportControlBlocks_with_fc_MX_and_DQC_REPORT_TYPE_should_create_dataset_and_controlblock_with_suffix_DQPO() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "PVOC", "1", null, "DoName2", Tfc.MX, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - // Check DataSet is created - DataSetAdapter dataSet = findDataSet(scd, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); - assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() - .usingRecursiveComparison().isEqualTo(toFCDA(tfcdaFilter)); - // Check ControlBlock is created - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); - - TReportControl reportControl = findControlBlock(scd, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); - assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, - TControlWithTriggerOpt::getIntgPd) - .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); - assertThat(reportControl.getTrgOps()) - .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) - .containsExactly(true, true, false, true, true); - assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); - assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); - } - - @Test - void createAllIhmReportControlBlocks_with_FCDA_on_ln0_should_create_dataset_and_controlblock() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "LLN0", null, null, "DoName0", Tfc.ST, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - // Check DataSet is created - DataSetAdapter dataSet = findDataSet(scd, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); - assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() - .usingRecursiveComparison().isEqualTo(toFCDA(tfcdaFilter)); - // Check ControlBlock is created - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); - TReportControl reportControl = findControlBlock(scd, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); - assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, - TControlWithTriggerOpt::getIntgPd) - .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); - assertThat(reportControl.getTrgOps()) - .extracting(TTrgOps::isDchg, TTrgOps::isQchg, TTrgOps::isDupd, TTrgOps::isPeriod, TTrgOps::isGi) - .containsExactly(true, true, false, true, true); - assertThat(reportControl.getRptEnabled().getMax()).isEqualTo(1); - assertThat(reportControl.getRptEnabled().isSetClientLN()).isFalse(); - } - - @Test - void createAllIhmReportControlBlocks_when_lDevice_ON_but_LN_Mod_StVal_missing_should_create_dataset_and_controlblock() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - LNAdapter ln = findLn(scd, "IedName1", "LdInst11", "ANCR", "1", null); - ln.getCurrentElem().unsetDOI(); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "ANCR", "1", null, "DoName1", Tfc.ST, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - // Check DataSet is created - DataSetAdapter dataSet = findDataSet(scd, "IedName1", "LdInst11", "DS_LDINST11_DQPO"); - assertThat(dataSet.getCurrentElem().getFCDA()).hasSize(1).first() - .usingRecursiveComparison().isEqualTo(toFCDA(tfcdaFilter)); - // Check ControlBlock is created - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - assertThat(ln0.getTControlsByType(TReportControl.class)).hasSize(1); - TReportControl reportControl = findControlBlock(scd, "IedName1", "LdInst11", "CB_LDINST11_DQPO", TReportControl.class); - assertThat(reportControl).extracting(TReportControl::getRptID, TControl::getDatSet, TReportControl::getConfRev, TReportControl::isBuffered, TReportControl::getBufTime, TReportControl::isIndexed, - TControlWithTriggerOpt::getIntgPd) - .containsExactly("IedName1LdInst11/LLN0.CB_LDINST11_DQPO", "DS_LDINST11_DQPO", 1L, true, 0L, true, 60000L); - } - - @Test - void createAllIhmReportControlBlocks_when_lDevice_ON_but_LN_Mod_StVal_OFF_should_not_create_dataset() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - LNAdapter ln = findLn(scd, "IedName1", "LdInst11", "ANCR", "1", null); - ln.getDOIAdapterByName(CommonConstants.MOD_DO_NAME).getDataAdapterByName(CommonConstants.STVAL_DA_NAME).setVal("off"); - assertThat(ln.getDaiModStValValue()).hasValue("off"); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "ANCR", "1", null, "DoName1", Tfc.ST, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - assertThat(streamAllDataSets(scd)).isEmpty(); - assertThat(streamAllControlBlocks(scd, TReportControl.class)).isEmpty(); - } - - @Test - void createAllIhmReportControlBlocks_when_lDevice_OFF_should_not_create_dataset() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - ln0.getDOIAdapterByName(CommonConstants.MOD_DO_NAME).getDataAdapterByName(CommonConstants.STVAL_DA_NAME).setVal("off"); - assertThat(findLDevice(scd, "IedName1", "LdInst11").getLDeviceStatus()).hasValue(ActiveStatus.OFF.getValue()); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "ANCR", "1", null, "DoName1", Tfc.ST, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - assertThat(streamAllDataSets(scd)).isEmpty(); - assertThat(streamAllControlBlocks(scd, TReportControl.class)).isEmpty(); - } - - @Test - void createAllIhmReportControlBlocks_when_LDevice_has_no_status_should_not_create_dataset() { - // Given - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml"); - LN0Adapter ln0 = findLn0(scd, "IedName1", "LdInst11"); - ln0.getDOIAdapterByName(CommonConstants.MOD_DO_NAME).getDataAdapterByName(CommonConstants.STVAL_DA_NAME).getCurrentElem().unsetVal(); - assertThat(findLDevice(scd, "IedName1", "LdInst11").getLDeviceStatus()).isEmpty(); - TFCDAFilter tfcdaFilter = createFCDAFilter("LdInst11", "ANCR", "1", null, "DoName1", Tfc.ST, DQC_REPORT_TYPE); - po.getFCDAs().getFCDA().add(tfcdaFilter); - // When - hmiService.createAllHmiReportControlBlocks(scd, po); - // Then - assertThat(streamAllDataSets(scd)).isEmpty(); - assertThat(streamAllControlBlocks(scd, TReportControl.class)).isEmpty(); - } - - private static TFCDAFilter createFCDAFilter(String ldInst, String lnClass, String lnInst, String prefix, String doName, Tfc tfc, String reportType) { - TFCDAFilter tfcdaFilter = new TFCDAFilter(); - tfcdaFilter.setLdInst(ldInst); - tfcdaFilter.setLnClass(lnClass); - tfcdaFilter.setPrefix(prefix); - tfcdaFilter.setDoName(doName); - tfcdaFilter.setLnInst(lnInst); - tfcdaFilter.setFc(tfc); - tfcdaFilter.setReportType(reportType); - return tfcdaFilter; - } - - private static TFCDA toFCDA(TFCDAFilter tfcdaFilter) { - TFCDA tfcda = new TFCDA(); - tfcda.setLdInst(tfcdaFilter.getLdInst()); - tfcda.getLnClass().add(tfcdaFilter.getLnClass()); - tfcda.setPrefix(tfcdaFilter.getPrefix()); - tfcda.setLnInst(tfcdaFilter.getLnInst()); - tfcda.setDoName(tfcdaFilter.getDoName()); - tfcda.setFc(TFCEnum.fromValue(tfcdaFilter.getFc().value())); - return tfcda; - } - -} diff --git a/sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml b/sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml deleted file mode 100644 index e50105482..000000000 --- a/sct-commons/src/test/resources/scd-hmi-create-report-cb/scd_create_dataset_and_controlblocks_for_hmi.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - -
- - - - - - - - - - - - - on - - - - - - - on - - - - - - - on - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - on - off - test - - - From e412abe241c662a0ad38b6f459e24a6a3f28e814 Mon Sep 17 00:00:00 2001 From: Samir Romdhani Date: Thu, 3 Oct 2024 15:26:36 +0200 Subject: [PATCH 3/3] feat: add voltage level service Signed-off-by: Samir Romdhani --- .../SclAutomationServiceIntegrationTest.java | 7 +-- .../compas/sct/commons/SubstationService.java | 54 +++++++++---------- .../sct/commons/VoltageLevelService.java | 29 ++++++++++ .../sct/commons/SubstationServiceTest.java | 9 ++-- .../sct/commons/VoltageLevelServiceTest.java | 48 +++++++++++++++++ 5 files changed, 108 insertions(+), 39 deletions(-) create mode 100644 sct-commons/src/main/java/org/lfenergy/compas/sct/commons/VoltageLevelService.java create mode 100644 sct-commons/src/test/java/org/lfenergy/compas/sct/commons/VoltageLevelServiceTest.java 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 fb4ec7c6e..33ab8ce65 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,10 +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.ControlBlockEditorService; -import org.lfenergy.compas.sct.commons.LdeviceService; -import org.lfenergy.compas.sct.commons.SclService; -import org.lfenergy.compas.sct.commons.SubstationService; +import org.lfenergy.compas.sct.commons.*; import org.lfenergy.compas.sct.commons.api.ControlBlockEditor; import org.lfenergy.compas.sct.commons.api.SclEditor; import org.lfenergy.compas.sct.commons.api.SubstationEditor; @@ -34,7 +31,7 @@ class SclAutomationServiceIntegrationTest { private SclAutomationService sclAutomationService ; private static final SclEditor sclEditor = new SclService() ; - private static final SubstationEditor substationEditor = new SubstationService() ; + private static final SubstationEditor substationEditor = new SubstationService(new VoltageLevelService()) ; private static final ControlBlockEditor controlBlockEditor = new ControlBlockEditorService(new ControlService(), new LdeviceService()) ; private HeaderDTO headerDTO; diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SubstationService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SubstationService.java index 1e51e398e..6936955ec 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SubstationService.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/SubstationService.java @@ -5,18 +5,19 @@ package org.lfenergy.compas.sct.commons; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import org.lfenergy.compas.scl2007b4.model.SCL; import org.lfenergy.compas.scl2007b4.model.TBay; import org.lfenergy.compas.scl2007b4.model.TSubstation; import org.lfenergy.compas.scl2007b4.model.TVoltageLevel; import org.lfenergy.compas.sct.commons.api.SubstationEditor; import org.lfenergy.compas.sct.commons.exception.ScdException; -import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; -import org.lfenergy.compas.sct.commons.scl.sstation.SubstationAdapter; -import org.lfenergy.compas.sct.commons.scl.sstation.VoltageLevelAdapter; +@RequiredArgsConstructor public class SubstationService implements SubstationEditor { + private final VoltageLevelService voltageLevelService; + @Override public void addSubstation(@NonNull SCL scd, @NonNull SCL ssd) throws ScdException { if (scd.getSubstation().size() > 1) { @@ -25,53 +26,48 @@ public void addSubstation(@NonNull SCL scd, @NonNull SCL ssd) throws ScdExceptio if (ssd.getSubstation().size() != 1) { throw new ScdException(String.format("SSD file must have exactly 1 Substation, but got %d", ssd.getSubstation().size())); } - TSubstation ssdTSubstation = ssd.getSubstation().get(0); + TSubstation ssdTSubstation = ssd.getSubstation().getFirst(); if (scd.getSubstation().isEmpty()) { scd.getSubstation().add(ssdTSubstation); } else { - TSubstation scdTSubstation = scd.getSubstation().get(0); - if (scdTSubstation.getName().equalsIgnoreCase(ssdTSubstation.getName())) { - SubstationAdapter scdSubstationAdapter = new SclRootAdapter(scd).getSubstationAdapter(scdTSubstation.getName()); + TSubstation scdTSubstation = scd.getSubstation().getFirst(); + if (scdTSubstation.getName().equalsIgnoreCase(ssdTSubstation.getName())){ for (TVoltageLevel tvl : ssdTSubstation.getVoltageLevel()) { - updateVoltageLevel(scdSubstationAdapter, tvl); + updateVoltageLevel(scd, tvl); } - } else + } else { throw new ScdException("SCD file must have only one Substation and the Substation name from SSD file is" + " different from the one in SCD file. The files are rejected."); + } } } /** * Creates new VoltageLevel section or updates VoltageLevel contents - * @param scdSubstationAdapter Substation in which VoltageLevel should be created/updated + * @param scd SCL contain Substation in which VoltageLevel should be created/updated * @param vl VoltageLevel to create/update * @throws ScdException throws when unable to create new VoltageLevel section which is not already present in Substation */ - private void updateVoltageLevel(@NonNull SubstationAdapter scdSubstationAdapter, TVoltageLevel vl) throws ScdException { - if (scdSubstationAdapter.getVoltageLevelAdapter(vl.getName()).isPresent()) { - VoltageLevelAdapter scdVoltageLevelAdapter = scdSubstationAdapter.getVoltageLevelAdapter(vl.getName()) - .orElseThrow(() -> new ScdException("Unable to create VoltageLevelAdapter")); - for (TBay tbay : vl.getBay()) { - updateBay(scdVoltageLevelAdapter, tbay); - } - } else { - scdSubstationAdapter.getCurrentElem().getVoltageLevel().add(vl); - } + private void updateVoltageLevel(@NonNull SCL scd, TVoltageLevel vl) throws ScdException { + voltageLevelService.findVoltageLevel(scd, tVoltageLevel -> tVoltageLevel.getName().equals(vl.getName())) + .ifPresentOrElse(tVoltageLevel -> vl.getBay().forEach(tBay -> updateBay(tVoltageLevel, tBay)), + ()-> scd.getSubstation().getFirst().getVoltageLevel().add(vl)); } + /** * Adds new Bay in VoltageLevel or if already exist removes and replaces it - * @param scdVoltageLevelAdapter VoltageLevel in which Bay should be created/updated + * @param tVoltageLevel VoltageLevel in which Bay should be created/updated * @param tBay Bay to add */ - private void updateBay(@NonNull VoltageLevelAdapter scdVoltageLevelAdapter, TBay tBay) { - if (scdVoltageLevelAdapter.getBayAdapter(tBay.getName()).isPresent()) { - scdVoltageLevelAdapter.getCurrentElem().getBay() - .removeIf(t -> t.getName().equalsIgnoreCase(tBay.getName())); - scdVoltageLevelAdapter.getCurrentElem().getBay().add(tBay); - } else { - scdVoltageLevelAdapter.getCurrentElem().getBay().add(tBay); - } + private void updateBay(@NonNull TVoltageLevel tVoltageLevel, TBay tBay) { + tVoltageLevel.getBay() + .stream().filter(tBay1 -> tBay1.getName().equals(tBay.getName())) + .findFirst() + .ifPresentOrElse(tBay1 -> { + tVoltageLevel.getBay().removeIf(t -> t.getName().equalsIgnoreCase(tBay.getName())); + tVoltageLevel.getBay().add(tBay); + }, ()-> tVoltageLevel.getBay().add(tBay)); } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/VoltageLevelService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/VoltageLevelService.java new file mode 100644 index 000000000..7778c62cb --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/VoltageLevelService.java @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons; + +import org.lfenergy.compas.scl2007b4.model.*; + +import java.util.Collection; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class VoltageLevelService { + + public Stream getVoltageLevels(SCL scd) { + if (!scd.isSetSubstation()) { + return Stream.empty(); + } + return scd.getSubstation() + .stream() + .map(TSubstation::getVoltageLevel) + .flatMap(Collection::stream); + } + + public Optional findVoltageLevel(SCL scd, Predicate tVoltageLevelPredicate) { + return getVoltageLevels(scd).filter(tVoltageLevelPredicate).findFirst(); + } +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SubstationServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SubstationServiceTest.java index 5ebba1c52..8134b2908 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SubstationServiceTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/SubstationServiceTest.java @@ -12,17 +12,16 @@ import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; -@ExtendWith(MockitoExtension.class) class SubstationServiceTest { - @InjectMocks - SubstationService substationService; + private final SubstationService substationService = new SubstationService(new VoltageLevelService()); @Test void addSubstation_when_SCD_has_no_substation_should_succeed() { @@ -43,8 +42,8 @@ void addSubstation_when_SCD_has_a_substation_should_succeed() { // Given SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/scd_with_substation.xml"); SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); - TSubstation scdSubstation = scd.getSubstation().get(0); - TSubstation ssdSubstation = ssd.getSubstation().get(0); + TSubstation scdSubstation = scd.getSubstation().getFirst(); + TSubstation ssdSubstation = ssd.getSubstation().getFirst(); assertThat(scdSubstation.getVoltageLevel().stream().map(TVoltageLevel::getBay).count()).isEqualTo(1); // When substationService.addSubstation(scd, ssd); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/VoltageLevelServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/VoltageLevelServiceTest.java new file mode 100644 index 000000000..643edfde9 --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/VoltageLevelServiceTest.java @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2024 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.SCL; +import org.lfenergy.compas.scl2007b4.model.TVoltageLevel; +import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +class VoltageLevelServiceTest { + + private final VoltageLevelService voltageLevelService = new VoltageLevelService(); + + @Test + void getVoltageLevels_should_succeed() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); + // When + List tVoltageLevels = voltageLevelService.getVoltageLevels(scd).toList(); + // Then + assertThat(tVoltageLevels).hasSize(2); + } + + @Test + void findVoltageLevel_when_voltageLevelExist_should_succeed() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); + // When Then + assertThatCode(() -> voltageLevelService.findVoltageLevel(scd, tVoltageLevel1 -> "4".equals(tVoltageLevel1.getName())).orElseThrow()) + .doesNotThrowAnyException(); + } + + @Test + void findVoltageLevel_when_voltageLevelNotExist_should_return_empty() { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); + // When Then + assertThat(voltageLevelService.findVoltageLevel(scd, tVoltageLevel1 -> "5".equals(tVoltageLevel1.getName()))) + .isEmpty(); + } +} \ No newline at end of file