diff --git a/pom.xml b/pom.xml index 769f09f99..691f13b8b 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,8 @@ sct-coverage/** ../sct-coverage/target/site/jacoco-aggregate/jacoco.xml ${basedir}/${aggregate.report.dir} + 0.9.1 + 0.0.4 @@ -71,7 +73,12 @@ org.lfenergy.compas.core scl-extension - 0.8.0 + ${scl-extension.version} + + + org.lfenergy.compas.xsd + compas-scl-xsd + ${compas-scl-xsd.version} ch.qos.logback @@ -104,6 +111,16 @@ + + org.lfenergy.compas.xsd + compas-scl-xsd + ${compas-scl-xsd.version} + + + org.lfenergy.compas.core + scl-extension + ${scl-extension.version} + org.apache.maven.plugins maven-compiler-plugin @@ -119,6 +136,11 @@ maven-surefire-plugin 2.22.2 + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + diff --git a/sct-app/pom.xml b/sct-app/pom.xml index d8a715842..286393e04 100644 --- a/sct-app/pom.xml +++ b/sct-app/pom.xml @@ -13,7 +13,6 @@ local-SNAPSHOT - org.lfenergy.compas sct-app local-SNAPSHOT SCT-APP @@ -112,7 +111,10 @@ org.lfenergy.compas.xsd compas-scl-xsd - 0.0.4 + + + org.lfenergy.compas.core + scl-extension org.lfenergy.compas.core diff --git a/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java b/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java index b8840930a..3abd95ebf 100644 --- a/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java +++ b/sct-app/src/main/java/org/lfenergy/compas/sct/app/SclAutomationService.java @@ -13,6 +13,7 @@ import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; import org.lfenergy.compas.sct.commons.scl.SclService; +import org.lfenergy.compas.sct.commons.scl.SubstationService; import java.util.*; @@ -32,7 +33,7 @@ public static SclRootAdapter createSCD(@NonNull SCL ssd, @NonNull HeaderDTO head HeaderDTO.HistoryItem hItem = headerDTO.getHistoryItems().get(0); SclService.addHistoryItem(scdAdapter.getCurrentElem(), hItem.getWho(), hItem.getWhat(), hItem.getWhy()); } - SclService.addSubstation(scdAdapter.getCurrentElem(), ssd); + SubstationService.addSubstation(scdAdapter.getCurrentElem(), ssd); SclService.importSTDElementsInSCD(scdAdapter, stds, comMap); return scdAdapter; } diff --git a/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java b/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java index 6aecfd219..84e413104 100644 --- a/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java +++ b/sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java @@ -17,6 +17,7 @@ import java.util.Set; import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; class SclAutomationServiceTest { @@ -30,20 +31,25 @@ void init(){ } @Test - void createSCD() throws Exception { + void createSCD_should_return_generatedSCD() throws Exception { + // Given SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/scd.xml"); SCL std = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/std.xml"); + // When SclRootAdapter expectedSCD = SclAutomationService.createSCD(ssd, headerDTO, Set.of(std)); + // Then assertNotNull(expectedSCD.getCurrentElem().getHeader().getId()); assertNull(expectedSCD.getCurrentElem().getHeader().getHistory()); assertEquals(1, expectedSCD.getCurrentElem().getSubstation().size()); assertEquals(1, expectedSCD.getCurrentElem().getIED().size()); assertNotNull(expectedSCD.getCurrentElem().getDataTypeTemplates()); assertEquals(2, expectedSCD.getCurrentElem().getCommunication().getSubNetwork().size()); + assertIsMarshallable(expectedSCD.getCurrentElem()); } @Test void createSCD_With_HItem() throws Exception { + // Given HeaderDTO.HistoryItem historyItem = new HeaderDTO.HistoryItem(); historyItem.setWhat("what"); historyItem.setWho("me"); @@ -53,14 +59,18 @@ void createSCD_With_HItem() throws Exception { SCL std1 = SclTestMarshaller.getSCLFromFile("/std_1.xml"); SCL std2 = SclTestMarshaller.getSCLFromFile("/std_2.xml"); SCL std3 = SclTestMarshaller.getSCLFromFile("/std_3.xml"); + // When SclRootAdapter expectedSCD = SclAutomationService.createSCD(ssd, headerDTO, Set.of(std1, std2, std3)); + // Then assertNotNull(expectedSCD.getCurrentElem().getHeader().getId()); assertEquals(1 ,expectedSCD.getCurrentElem().getHeader().getHistory().getHitem().size()); assertEquals(1, expectedSCD.getCurrentElem().getSubstation().size()); + assertIsMarshallable(expectedSCD.getCurrentElem()); } @Test void createSCD_With_HItems() throws Exception { + // Given HeaderDTO.HistoryItem historyItem = new HeaderDTO.HistoryItem(); historyItem.setWhat("what"); historyItem.setWho("me"); @@ -74,17 +84,22 @@ void createSCD_With_HItems() throws Exception { SCL std1 = SclTestMarshaller.getSCLFromFile("/std_1.xml"); SCL std2 = SclTestMarshaller.getSCLFromFile("/std_2.xml"); SCL std3 = SclTestMarshaller.getSCLFromFile("/std_3.xml"); + // When SclRootAdapter expectedSCD = SclAutomationService.createSCD(ssd, headerDTO,Set.of(std1, std2, std3)); + // Then assertNotNull(expectedSCD.getCurrentElem().getHeader().getId()); assertEquals(1, expectedSCD.getCurrentElem().getHeader().getHistory().getHitem().size()); assertEquals("what", expectedSCD.getCurrentElem().getHeader().getHistory().getHitem().get(0).getWhat()); + assertIsMarshallable(expectedSCD.getCurrentElem()); } @Test void createSCD_SSD_Without_Substation() throws Exception { + // Given SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd_without_substations.xml"); + // When & Then assertThrows(ScdException.class, () -> SclAutomationService.createSCD(ssd, headerDTO, new HashSet<>()) ); } -} \ No newline at end of file +} diff --git a/sct-commons/pom.xml b/sct-commons/pom.xml index 1eaf5f727..f47ecc126 100644 --- a/sct-commons/pom.xml +++ b/sct-commons/pom.xml @@ -32,7 +32,7 @@ org.apache.commons commons-lang3 - 3.11 + 3.12.0 jakarta.xml.bind @@ -112,6 +112,7 @@ test + @@ -166,7 +167,10 @@ org.lfenergy.compas.xsd compas-scl-xsd - 0.0.4 + + + org.lfenergy.compas.core + scl-extension org.lfenergy.compas.core @@ -196,6 +200,9 @@ ${project.build.directory}/xsd/SCL2007B4/SCL.xsd ${project.build.directory}/xsd/SCL_CoMPAS.xsd + + ${project.basedir}/src/main/resources/binding_configuration.xjb + org.lfenergy.compas.scl2007b4.model true @@ -214,4 +221,4 @@ - \ No newline at end of file + diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/CommonConstants.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/CommonConstants.java deleted file mode 100644 index 90dcd01b9..000000000 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/CommonConstants.java +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: 2021 RTE FRANCE -// -// SPDX-License-Identifier: Apache-2.0 - -package org.lfenergy.compas.sct.commons; - -public class CommonConstants { - CommonConstants() { - throw new UnsupportedOperationException("CommonConstants class"); - } - - public static final String XML_DEFAULT_NS_PREFIX = "scl"; - public static final String XML_DEFAULT_NS_URI = "http://www.iec.ch/61850/2003/SCL"; - public static final String XML_DEFAULT_XSD_PATH = "classpath:schema/SCL.xsd"; - - public static final String COMPAS_SCL_FILE_TYPE = "COMPAS-SclFileType"; - public static final String SCL_FILE_TYPE = "SclFileType"; - public static final String COMPAS_ICDHEADER = "COMPAS-ICDHeader"; - public static final String ICD_SYSTEM_VERSION_UUID = "ICDSystemVersionUUID"; - public static final String IED_NAME = "IEDName"; - public static final String HEADER_ID = "headerId"; - public static final String HEADER_VERSION = "headerVersion"; - public static final String HEADER_REVISION = "headerRevision"; - public static final String IED_TYPE = "IEDType"; - public static final String VENDOR_NAME = "VendorName"; - public static final String IED_REDUNDANCY = "IEDredundancy"; - public static final String IED_MODEL = "IEDmodel"; - public static final String HW_REV = "hwRev"; - public static final String SW_REV = "swRev"; - -} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/Utils.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/Utils.java deleted file mode 100644 index 91703eb81..000000000 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/Utils.java +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-FileCopyrightText: 2021 RTE FRANCE -// -// SPDX-License-Identifier: Apache-2.0 - -package org.lfenergy.compas.sct.commons; - -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.Field; - -@Slf4j -public class Utils { - - private Utils() { - throw new IllegalStateException("Utils class"); - } - - public static String entering(){ - return ">>> " + - "Entering: " + - "-::" + - getMethodName(); - } - - public static String leaving(Long startTime){ - if(startTime == null || startTime <= 0){ - return leaving(); - } - return "<<< " + - "Leaving: " + - "-::" + - getMethodName() + - " - Timer duration: " + - (System.nanoTime() - startTime) / Math.pow(10, 9) + - " sec."; - } - - public static String getMethodName() { - try { - return (new Throwable()).getStackTrace()[2].getMethodName(); - } catch (Exception e){ - return "-"; - } - } - - public static String leaving(){ - return "<<< " + - "Leaving: " + - "::" + - getMethodName(); - } - - /** - * Returns the first {@link Field} in the hierarchy for the specified name - */ - public static Field getField(Class clazz, String name) { - Field field = null; - while (clazz != null && field == null) { - try { - field = clazz.getDeclaredField(name); - } catch (Exception e) { - log.error("Cannot find field name {}", name, e); - } - clazz = clazz.getSuperclass(); - } - return field; - } - - /** - * Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name - */ - public static void setField(Object object, String fieldName, Object value) { - try { - Field field = getField(object.getClass(), fieldName); - if(field != null){ - field.setAccessible(true); - field.set(object, value); - } - } catch (Exception e) { - log.error("Cannot nullify {} : ",fieldName, e); - } - } -} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlock.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlock.java index 5d3352fdc..ca09a625a 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlock.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/ControlBlock.java @@ -7,14 +7,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.lfenergy.compas.scl2007b4.model.TClientLN; -import org.lfenergy.compas.scl2007b4.model.TControl; -import org.lfenergy.compas.scl2007b4.model.TControlWithIEDName; -import org.lfenergy.compas.scl2007b4.model.TPredefinedTypeOfSecurityEnum; -import org.lfenergy.compas.scl2007b4.model.TServiceSettingsNoDynEnum; -import org.lfenergy.compas.scl2007b4.model.TServiceType; -import org.lfenergy.compas.scl2007b4.model.TServices; -import org.lfenergy.compas.sct.commons.Utils; +import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter; @@ -79,14 +72,12 @@ public void validateDestination(SclRootAdapter sclRootAdapter) throws ScdExcepti ) ) ); - if(!iedName.getLnClass().isEmpty()) { + if (iedName.isSetLnClass()) { try { lDeviceAdapter.getLNAdapter(iedName.getLnClass().get(0), iedName.getLnInst(), iedName.getPrefix()); - } catch (ScdException e){ + } catch (ScdException e) { throw new ScdException("Control block destination: " + e.getMessage()); } - } else { - Utils.setField(iedName,"lnClass",null); } } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/DaTypeName.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/DaTypeName.java index ce5166612..a775c1e0e 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/DaTypeName.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/DaTypeName.java @@ -75,7 +75,7 @@ public void addDaiValues(List vals) { } public void addDaiValue(TVal val) { - if(val.getSGroup() == null){ + if(!val.isSetSGroup()){ daiValues.put(0L,val.getValue()); } else { daiValues.put(val.getSGroup(), val.getValue()); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/FCDAInfo.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/FCDAInfo.java index e62d3c3d7..de23eb520 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/FCDAInfo.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/FCDAInfo.java @@ -39,10 +39,9 @@ public FCDAInfo(String dataSet, TFCDA tfcda) { lnInst = tfcda.getLnInst(); doName = new DoTypeName(tfcda.getDoName()); daName = new DaTypeName(tfcda.getDaName()); - ix = tfcda.getIx(); + ix = tfcda.isSetIx() ? tfcda.getIx() : null; } - @JsonIgnore public TFCDA getFCDA(){ TFCDA tfcda = new TFCDA(); @@ -75,4 +74,4 @@ public TFCDA getFCDA(){ public boolean isValid() { return doName != null && doName.isDefined(); } -} \ No newline at end of file +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/GooseControlBlock.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/GooseControlBlock.java index d1d447ba1..ad683442c 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/GooseControlBlock.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/GooseControlBlock.java @@ -7,12 +7,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.lfenergy.compas.scl2007b4.model.TGSEControl; -import org.lfenergy.compas.scl2007b4.model.TMcSecurity; -import org.lfenergy.compas.scl2007b4.model.TPredefinedTypeOfSecurityEnum; -import org.lfenergy.compas.scl2007b4.model.TProtocol; -import org.lfenergy.compas.scl2007b4.model.TServiceType; -import org.lfenergy.compas.scl2007b4.model.TServices; +import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.exception.ScdException; @@ -27,7 +22,7 @@ public GooseControlBlock(TGSEControl tgseControl) { super(); this.id = tgseControl.getAppID(); this.name = tgseControl.getName(); - if(tgseControl.getConfRev() != null) { + if(tgseControl.isSetConfRev()) { this.confRev = tgseControl.getConfRev(); } this.desc = tgseControl.getDesc(); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDeviceDTO.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDeviceDTO.java index fbc91364f..22873f50a 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDeviceDTO.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LDeviceDTO.java @@ -6,12 +6,10 @@ import lombok.Getter; import lombok.NoArgsConstructor; - import lombok.extern.slf4j.Slf4j; -import org.lfenergy.compas.sct.commons.Utils; import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter; import org.lfenergy.compas.sct.commons.scl.ied.LNAdapter; - +import org.lfenergy.compas.sct.commons.util.Utils; import java.util.HashSet; import java.util.List; diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LNodeDTO.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LNodeDTO.java index 3892277b9..5cd8707d4 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LNodeDTO.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/LNodeDTO.java @@ -9,12 +9,12 @@ import lombok.extern.slf4j.Slf4j; import org.lfenergy.compas.scl2007b4.model.TAnyLN; import org.lfenergy.compas.scl2007b4.model.TExtRef; -import org.lfenergy.compas.sct.commons.Utils; import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter; import org.lfenergy.compas.sct.commons.scl.dtt.LNodeTypeAdapter; import org.lfenergy.compas.sct.commons.scl.ied.AbstractLNAdapter; import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter; import org.lfenergy.compas.sct.commons.scl.ied.LNAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; import java.util.HashSet; import java.util.List; diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/SMVControlBlock.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/SMVControlBlock.java index 51c2469ff..13abc6425 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/SMVControlBlock.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/SMVControlBlock.java @@ -7,13 +7,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.lfenergy.compas.scl2007b4.model.TMcSecurity; -import org.lfenergy.compas.scl2007b4.model.TPredefinedTypeOfSecurityEnum; -import org.lfenergy.compas.scl2007b4.model.TProtocol; -import org.lfenergy.compas.scl2007b4.model.TSampledValueControl; -import org.lfenergy.compas.scl2007b4.model.TServiceType; -import org.lfenergy.compas.scl2007b4.model.TServices; -import org.lfenergy.compas.scl2007b4.model.TSmpMod; +import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.exception.ScdException; import java.util.Collections; @@ -36,9 +30,7 @@ public SMVControlBlock(TSampledValueControl tSampledValueControl) { super(); this.id = tSampledValueControl.getSmvID(); this.name = tSampledValueControl.getName(); - if(tSampledValueControl.getConfRev() != null) { - this.confRev = tSampledValueControl.getConfRev(); - } + this.confRev = tSampledValueControl.isSetConfRev() ? tSampledValueControl.getConfRev() : null; this.desc = tSampledValueControl.getDesc(); this.dataSetRef = tSampledValueControl.getDatSet(); Collections.copy(iedNames, tSampledValueControl.getIEDName()); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/exception/ScdException.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/exception/ScdException.java index dcf62624d..5dd039631 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/exception/ScdException.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/exception/ScdException.java @@ -4,7 +4,10 @@ package org.lfenergy.compas.sct.commons.exception; -public class ScdException extends Exception { +/** + * Thrown when SCD is inconsistent + */ +public class ScdException extends RuntimeException { public ScdException(String message) { super(message); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/PrivateService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/PrivateService.java new file mode 100644 index 000000000..3a8aa96de --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/PrivateService.java @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.sct.commons.exception.ScdException; +import org.lfenergy.compas.sct.commons.util.PrivateEnum; + +import javax.xml.bind.JAXBElement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@Slf4j +public final class PrivateService { + + private PrivateService() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + private static final ObjectFactory objectFactory = new ObjectFactory(); + + public static List getCompasPrivates(List tPrivates, Class compasClass) throws ScdException { + PrivateEnum privateEnum = PrivateEnum.fromClass(compasClass); + List compasElements = tPrivates.stream().filter(tPrivate -> privateEnum.getPrivateType().equals(tPrivate.getType())) + .map(TAnyContentFromOtherNamespace::getContent).flatMap(List::stream) + .filter(JAXBElement.class::isInstance).map(JAXBElement.class::cast) + .filter(Predicate.not(JAXBElement::isNil)) + .map(JAXBElement::getValue).collect(Collectors.toList()); + + List result = new ArrayList<>(); + for (Object compasElement : compasElements) { + if (compasClass.isInstance(compasElement)) { + result.add(compasClass.cast(compasElement)); + } else { + throw new ScdException(String.format("Private is inconsistent. It has type=%s which expect JAXBElement<%s> content, " + + "but got JAXBElement<%s>", + privateEnum.getPrivateType(), privateEnum.getCompasClass().getName(), compasElement.getClass().getName())); + } + } + return result; + } + + public static List getCompasPrivates(TBaseElement baseElement, Class compasClass) throws ScdException { + if (!baseElement.isSetPrivate()) { + return Collections.emptyList(); + } + return getCompasPrivates(baseElement.getPrivate(), compasClass); + } + + public static Optional getCompasPrivate(TPrivate tPrivate, Class compasClass) throws ScdException { + List compasPrivates = getCompasPrivates(Collections.singletonList(tPrivate), compasClass); + if (compasPrivates.size() > 1) { + throw new ScdException(String.format("Expecting maximum 1 element of type %s in private %s, but got %d", + compasClass.getName(), tPrivate.getType(), compasPrivates.size())); + } + if (compasPrivates.isEmpty()) { + return Optional.empty(); + } + return Optional.of(compasPrivates.get(0)); + } + + public static Optional getCompasICDHeader(TPrivate tPrivate) throws ScdException { + return getCompasPrivate(tPrivate, TCompasICDHeader.class); + } + + public static void removePrivates(TBaseElement baseElement, @NonNull PrivateEnum privateEnum) { + if (baseElement.isSetPrivate()) { + baseElement.getPrivate().removeIf(tPrivate -> privateEnum.getPrivateType().equals(tPrivate.getType())); + if (baseElement.getPrivate().isEmpty()) { + baseElement.unsetPrivate(); + } + } + } + + public static TPrivate createPrivate(TCompasBay compasBay) { + return createPrivate(objectFactory.createBay(compasBay)); + } + + public static TPrivate createPrivate(TCompasCriteria compasCriteria) { + return createPrivate(objectFactory.createCriteria(compasCriteria)); + } + + public static TPrivate createPrivate(TCompasFlow compasFlow) { + return createPrivate(objectFactory.createFlow(compasFlow)); + } + + public static TPrivate createPrivate(TCompasFunction compasFunction) { + return createPrivate(objectFactory.createFunction(compasFunction)); + } + + public static TPrivate createPrivate(TCompasICDHeader compasICDHeader) { + return createPrivate(objectFactory.createICDHeader(compasICDHeader)); + } + + public static TPrivate createPrivate(TCompasLDevice compasLDevice) { + return createPrivate(objectFactory.createLDevice(compasLDevice)); + } + + public static TPrivate createPrivate(TCompasSclFileType compasSclFileType) { + return createPrivate(objectFactory.createSclFileType(compasSclFileType)); + } + + public static TPrivate createPrivate(TCompasSystemVersion compasSystemVersion) { + return createPrivate(objectFactory.createSystemVersion(compasSystemVersion)); + } + + private static TPrivate createPrivate(JAXBElement jaxbElement) { + PrivateEnum privateEnum = PrivateEnum.fromClass(jaxbElement.getDeclaredType()); + TPrivate tPrivate = new TPrivate(); + tPrivate.setType(privateEnum.getPrivateType()); + tPrivate.getContent().add(jaxbElement); + return tPrivate; + } + + + + + + + + + + + + } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclElementAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclElementAdapter.java index 7c09059d7..ad7a44cee 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclElementAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclElementAdapter.java @@ -5,6 +5,7 @@ package org.lfenergy.compas.sct.commons.scl; import lombok.Getter; +import org.lfenergy.compas.scl2007b4.model.TBaseElement; import org.lfenergy.compas.scl2007b4.model.TPrivate; @@ -43,7 +44,21 @@ public final void setCurrentElem(T currentElem){ protected abstract boolean amChildElementRef(); - protected abstract void addPrivate(TPrivate tPrivate); + public void addPrivate(TPrivate tPrivate){ + if (currentElem instanceof TBaseElement){ + ((TBaseElement) currentElem).getPrivate().add(tPrivate); + } else { + throw new UnsupportedOperationException("Not implemented for class " + this.getClass().getName()); + } + } -} + public String getXPath(){ + String parentXpath = (parentAdapter != null) ? parentAdapter.getXPath() : ""; + return parentXpath + "/" + elementXPath(); + } + protected String elementXPath(){ + return String.format("undefined(%s)", currentElem.getClass().getSimpleName()); + } + +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapter.java index cf36421d7..c2f7807eb 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapter.java @@ -54,8 +54,8 @@ protected boolean amChildElementRef() { } @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); + protected String elementXPath() { + return "SCL"; } public Short getSclRelease(){ diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java index f8266ac0f..068b8f6e3 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SclService.java @@ -7,10 +7,7 @@ import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; -import org.lfenergy.compas.scl.extensions.commons.CompasExtensionsConstants; import org.lfenergy.compas.scl2007b4.model.*; -import org.lfenergy.compas.sct.commons.CommonConstants; -import org.lfenergy.compas.sct.commons.Utils; import org.lfenergy.compas.sct.commons.dto.*; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.com.CommunicationAdapter; @@ -20,26 +17,22 @@ import org.lfenergy.compas.sct.commons.scl.dtt.EnumTypeAdapter; import org.lfenergy.compas.sct.commons.scl.dtt.LNodeTypeAdapter; import org.lfenergy.compas.sct.commons.scl.header.HeaderAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.AbstractLNAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.DAITracker; -import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter; -import org.lfenergy.compas.sct.commons.scl.sstation.SubstationAdapter; -import org.lfenergy.compas.sct.commons.scl.sstation.VoltageLevelAdapter; - -import javax.xml.bind.JAXBElement; -import javax.xml.namespace.QName; +import org.lfenergy.compas.sct.commons.scl.ied.*; +import org.lfenergy.compas.sct.commons.util.Utils; + import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; -import static org.lfenergy.compas.sct.commons.CommonConstants.ICD_SYSTEM_VERSION_UUID; +import static org.lfenergy.compas.sct.commons.util.CommonConstants.*; +import static org.lfenergy.compas.sct.commons.util.PrivateEnum.COMPAS_ICDHEADER; @Slf4j public class SclService { public static final String UNKNOWN_LDEVICE_S_IN_IED_S = "Unknown LDevice (%s) in IED (%s)"; public static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info"; + public static final ObjectFactory objectFactory = new ObjectFactory(); private SclService() { throw new IllegalStateException("SclService class"); @@ -48,20 +41,10 @@ private SclService() { public static SclRootAdapter initScl(Optional hId, String hVersion, String hRevision) throws ScdException { UUID headerId = hId.orElseGet(UUID::randomUUID); SclRootAdapter scdAdapter = new SclRootAdapter(headerId.toString(), hVersion, hRevision); - scdAdapter.addPrivate(initSclFileType()); + scdAdapter.addPrivate(PrivateService.createPrivate(TCompasSclFileType.SCD)); return scdAdapter; } - private static TPrivate initSclFileType() { - TPrivate fileTypePrivate = new TPrivate(); - fileTypePrivate.setType(CommonConstants.COMPAS_SCL_FILE_TYPE); - JAXBElement compasFileType = new JAXBElement<>( - new QName(CompasExtensionsConstants.COMPAS_EXTENSION_NS_URI, CommonConstants.SCL_FILE_TYPE), - TCompasSclFileType.class, TCompasSclFileType.SCD); - fileTypePrivate.getContent().add(compasFileType); - return fileTypePrivate; - } - public static SclRootAdapter addHistoryItem(SCL scd, String who, String what, String why) { SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); HeaderAdapter headerAdapter = sclRootAdapter.getHeaderAdapter(); @@ -70,7 +53,6 @@ public static SclRootAdapter addHistoryItem(SCL scd, String who, String what, St } public static SclRootAdapter updateHeader(@NonNull SCL scd, @NonNull HeaderDTO headerDTO) { - SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); HeaderAdapter headerAdapter = sclRootAdapter.getHeaderAdapter(); @@ -151,7 +133,6 @@ public static List getExtRefInfo(SCL scd, String iedName, String ldI return lDeviceAdapter.getExtRefInfo(); } - public static List getExtRefBinders(SCL scd, String iedName, String ldInst, String lnClass, String lnInst, String prefix, ExtRefSignalInfo signalInfo) throws ScdException { SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); @@ -206,10 +187,8 @@ public static void updateExtRefBinders(SCL scd, ExtRefInfo extRefInfo) throws Sc abstractLNAdapter.updateExtRefBinders(extRefInfo); } - public static List> getExtRefSourceInfo(SCL scd, ExtRefInfo extRefInfo) throws ScdException { - ExtRefSignalInfo signalInfo = extRefInfo.getSignalInfo(); if (!signalInfo.isValid()) { throw new ScdException("Invalid or missing attributes in ExtRef signal info"); @@ -329,7 +308,6 @@ public static void updateDAI(SCL scd, String iedName, String ldInst, ResumedData () -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)) ); - AbstractLNAdapter lnAdapter = AbstractLNAdapter.builder() .withLDeviceAdapter(lDeviceAdapter) .withLnClass(rDtt.getLnClass()) @@ -355,54 +333,6 @@ public static Set> getEnumTypeElements(SCL scd, String idE .collect(Collectors.toSet()); } - public static SclRootAdapter addSubstation(@NonNull SCL scd, @NonNull SCL ssd) throws ScdException { - SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); - SclRootAdapter ssdRootAdapter = new SclRootAdapter(ssd); - if (scdRootAdapter.getCurrentElem().getSubstation().size() > 1 - || ssdRootAdapter.currentElem.getSubstation().size() != 1) { - throw new ScdException("SCD file must have one or zero Substation and " + - "SCD file must have one Substation. The files are rejected."); - } - TSubstation ssdTSubstation = ssdRootAdapter.currentElem.getSubstation().get(0); - if (scdRootAdapter.getCurrentElem().getSubstation().isEmpty()) { - scdRootAdapter.getCurrentElem().getSubstation().add(ssdTSubstation); - return scdRootAdapter; - } else { - TSubstation scdTSubstation = scdRootAdapter.currentElem.getSubstation().get(0); - if (scdTSubstation.getName().equalsIgnoreCase(ssdTSubstation.getName())) { - SubstationAdapter scdSubstationAdapter = scdRootAdapter.getSubstationAdapter(scdTSubstation.getName()); - for (TVoltageLevel tvl : ssdTSubstation.getVoltageLevel()) { - updateVoltageLevel(scdSubstationAdapter, tvl); - } - } 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."); - } - return scdRootAdapter; - } - - private static 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 static 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); - } - } - public static SclRootAdapter importSTDElementsInSCD(@NonNull SclRootAdapter scdRootAdapter, Set stds, Map, List> comMap) throws ScdException { @@ -415,7 +345,7 @@ public static SclRootAdapter importSTDElementsInSCD(@NonNull SclRootAdapter scdR for (Map.Entry entry : mapIEDNameAndPrivate.entrySet()) { String iedName = entry.getKey(); TPrivate tPrivate = entry.getValue(); - String icdSysVerUuid = getCompasICDHeader(tPrivate).map(TCompasICDHeader::getICDSystemVersionUUID).orElseThrow( + String icdSysVerUuid = PrivateService.getCompasICDHeader(tPrivate).map(TCompasICDHeader::getICDSystemVersionUUID).orElseThrow( () -> new ScdException(ICD_SYSTEM_VERSION_UUID + " is not present in COMPAS-ICDHeader in LNode") ); @@ -425,7 +355,7 @@ public static SclRootAdapter importSTDElementsInSCD(@NonNull SclRootAdapter scdR SCL std = mapICDSystemVersionUuidAndSTDFile.get(icdSysVerUuid).getRight().get(0); SclRootAdapter stdRootAdapter = new SclRootAdapter(std); IEDAdapter stdIedAdapter = new IEDAdapter(stdRootAdapter, std.getIED().get(0)); - Optional optionalTPrivate = stdIedAdapter.getPrivateHeader(CommonConstants.COMPAS_ICDHEADER); + Optional optionalTPrivate = stdIedAdapter.getPrivateHeader(COMPAS_ICDHEADER.getPrivateType()); if (optionalTPrivate.isPresent() && comparePrivateCompasICDHeaders(optionalTPrivate.get(), tPrivate)) { copyCompasICDHeaderFromLNodePrivateIntoSTDPrivate(optionalTPrivate.get(), tPrivate); } else throw new ScdException("COMPAS-ICDHeader is not the same in Substation and in IED"); @@ -448,11 +378,12 @@ private static void checkSTDCorrespondanceWithLNodeCompasICDHeader(Map new ScdException(CommonConstants.COMPAS_ICDHEADER + "not found in LNode Private ")); - return iedCompasICDHeader.getIEDType().equals(scdCompasICDHeader.getIEDType()) + TCompasICDHeader iedCompasICDHeader = PrivateService.getCompasICDHeader(iedPrivate).orElseThrow( + () -> new ScdException(COMPAS_ICDHEADER + "not found in IED Private ")); + TCompasICDHeader scdCompasICDHeader = PrivateService.getCompasICDHeader(scdPrivate).orElseThrow( + () -> new ScdException(COMPAS_ICDHEADER + "not found in LNode Private ")); + return iedCompasICDHeader.getIEDType().equals(scdCompasICDHeader.getIEDType()) && iedCompasICDHeader.getICDSystemVersionUUID().equals(scdCompasICDHeader.getICDSystemVersionUUID()) && iedCompasICDHeader.getVendorName().equals(scdCompasICDHeader.getVendorName()) && iedCompasICDHeader.getIEDredundancy().equals(scdCompasICDHeader.getIEDredundancy()) @@ -498,20 +429,29 @@ private static boolean comparePrivateCompasICDHeaders(TPrivate iedPrivate, TPriv } private static void copyCompasICDHeaderFromLNodePrivateIntoSTDPrivate(TPrivate stdPrivate, TPrivate lNodePrivate) throws ScdException { - TCompasICDHeader lNodeCompasICDHeader = getCompasICDHeader(lNodePrivate).orElseThrow( - () -> new ScdException(CommonConstants.COMPAS_ICDHEADER + "not found in LNode Private ")); + TCompasICDHeader lNodeCompasICDHeader = PrivateService.getCompasICDHeader(lNodePrivate).orElseThrow( + () -> new ScdException(COMPAS_ICDHEADER + " not found in LNode Private ")); stdPrivate.getContent().clear(); - stdPrivate.getContent().add(lNodeCompasICDHeader); - + stdPrivate.getContent().add(objectFactory.createICDHeader(lNodeCompasICDHeader)); } - private static Optional getCompasICDHeader(TPrivate tPrivate) { - Optional> tCompasICDHeader = !tPrivate.getType().equals(CommonConstants.COMPAS_ICDHEADER) ? Optional.empty() : - tPrivate.getContent().stream() - .filter(JAXBElement.class::isInstance) - .map(o -> (JAXBElement) o) - .findFirst(); - return tCompasICDHeader.map(JAXBElement::getValue); + public static void removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(final SCL scl) { + SclRootAdapter sclRootAdapter = new SclRootAdapter(scl); + List lDeviceAdapters = sclRootAdapter.getIEDAdapters().stream() + .map(IEDAdapter::getLDeviceAdapters).flatMap(List::stream).collect(Collectors.toList()); + + // LN0 + lDeviceAdapters.stream() + .map(LDeviceAdapter::getLN0Adapter) + .forEach(ln0 -> { + ln0.removeAllControlBlocksAndDatasets(); + ln0.removeAllExtRefSourceBindings(); + }); + + // Other LN + lDeviceAdapters.stream() + .map(LDeviceAdapter::getLNAdapters).flatMap(List::stream) + .forEach(LNAdapter::removeAllControlBlocksAndDatasets); } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SubstationService.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SubstationService.java new file mode 100644 index 000000000..3b27c0afe --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/SubstationService.java @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2021 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +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.exception.ScdException; +import org.lfenergy.compas.sct.commons.scl.sstation.BayAdapter; +import org.lfenergy.compas.sct.commons.scl.sstation.FunctionAdapter; +import org.lfenergy.compas.sct.commons.scl.sstation.SubstationAdapter; +import org.lfenergy.compas.sct.commons.scl.sstation.VoltageLevelAdapter; + +@Slf4j +public final class SubstationService { + + private SubstationService() { + throw new UnsupportedOperationException("This service class cannot be instantiated"); + } + + public static SclRootAdapter addSubstation(@NonNull SCL scd, @NonNull SCL ssd) throws ScdException { + SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); + SclRootAdapter ssdRootAdapter = new SclRootAdapter(ssd); + if (scdRootAdapter.getCurrentElem().getSubstation().size() > 1) { + throw new ScdException(String.format("SCD file must have 0 or 1 Substation, but got %d", + scdRootAdapter.getCurrentElem().getSubstation().size())); + } + if (ssdRootAdapter.getCurrentElem().getSubstation().size() != 1) { + throw new ScdException(String.format("SSD file must have exactly 1 Substation, but got %d", + ssdRootAdapter.getCurrentElem().getSubstation().size())); + } + TSubstation ssdTSubstation = ssdRootAdapter.currentElem.getSubstation().get(0); + if (scdRootAdapter.getCurrentElem().getSubstation().isEmpty()) { + scdRootAdapter.getCurrentElem().getSubstation().add(ssdTSubstation); + return scdRootAdapter; + } else { + TSubstation scdTSubstation = scdRootAdapter.currentElem.getSubstation().get(0); + if (scdTSubstation.getName().equalsIgnoreCase(ssdTSubstation.getName())) { + SubstationAdapter scdSubstationAdapter = scdRootAdapter.getSubstationAdapter(scdTSubstation.getName()); + for (TVoltageLevel tvl : ssdTSubstation.getVoltageLevel()) { + updateVoltageLevel(scdSubstationAdapter, tvl); + } + } 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."); + } + return scdRootAdapter; + } + + private static 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 static 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); + } + } + + public static void updateLNodeIEDNames(SCL scd) throws ScdException { + if (!scd.isSetSubstation()) { + return; + } + SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); + + scd.getSubstation().stream().map(tSubstation -> new SubstationAdapter(sclRootAdapter, tSubstation)) + .flatMap(SubstationAdapter::streamVoltageLevelAdapters) + .flatMap(VoltageLevelAdapter::streamBayAdapters) + .flatMap(BayAdapter::streamFunctionAdapters) + .forEach(FunctionAdapter::updateLNodeIedNames); + } +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/CommunicationAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/CommunicationAdapter.java index 37d54dd67..e4b5caf42 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/CommunicationAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/CommunicationAdapter.java @@ -6,7 +6,6 @@ import org.lfenergy.compas.scl2007b4.model.TCommunication; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.scl2007b4.model.TSubNetwork; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -33,11 +32,6 @@ public boolean amChildElementRef() { return currentElem == parentAdapter.getCurrentElem().getCommunication(); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public SubNetworkAdapter addSubnetwork(String snName, String snType, String iedName, String apName) throws ScdException { diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/ConnectedAPAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/ConnectedAPAdapter.java index 280b15fba..e62b5962e 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/ConnectedAPAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/ConnectedAPAdapter.java @@ -6,7 +6,6 @@ import org.lfenergy.compas.scl2007b4.model.SCL; import org.lfenergy.compas.scl2007b4.model.TConnectedAP; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import java.util.Optional; @@ -22,11 +21,6 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getConnectedAP().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public String getIedName() { return currentElem.getIedName(); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/SubNetworkAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/SubNetworkAdapter.java index 1d34883d6..4f06df43a 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/SubNetworkAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/com/SubNetworkAdapter.java @@ -6,7 +6,6 @@ import lombok.NonNull; import org.lfenergy.compas.scl2007b4.model.TConnectedAP; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.scl2007b4.model.TSubNetwork; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -26,11 +25,6 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getSubNetwork().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - /** * Create a Connected Access Point for this subnetwork. * Note : this method doesn't check the validity on neither the IED name nor the access point name. diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/AbstractDataAttributeAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/AbstractDataAttributeAdapter.java index e3e29e5b5..e0d745d32 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/AbstractDataAttributeAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/AbstractDataAttributeAdapter.java @@ -5,15 +5,11 @@ package org.lfenergy.compas.sct.commons.scl.dtt; import lombok.Getter; -import org.lfenergy.compas.scl2007b4.model.TAbstractDataAttribute; -import org.lfenergy.compas.scl2007b4.model.TDA; -import org.lfenergy.compas.scl2007b4.model.TPredefinedBasicTypeEnum; -import org.lfenergy.compas.scl2007b4.model.TProtNs; -import org.lfenergy.compas.scl2007b4.model.TVal; -import org.lfenergy.compas.sct.commons.Utils; +import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.dto.DaTypeName; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; import java.util.Objects; import java.util.Optional; @@ -48,7 +44,6 @@ public Optional getDATypeAdapter() { public boolean hasSameContentAs(T data) { - final String countField = "count"; if(!Objects.equals(getName(),data.getName()) || !Objects.equals(getBType(),data.getBType()) || !Objects.equals(getType(),data.getType()) @@ -67,19 +62,11 @@ public boolean hasSameContentAs(T data) { return false; } } - if(!Objects.equals(currentElem.getCount(),data.getCount())){ - if(currentElem.getCount().isEmpty()){ - Utils.setField(currentElem,countField,null); - } - if(data.getCount().isEmpty()){ - Utils.setField(data,countField,null); - } - return false ; - } else if(currentElem.getCount().isEmpty()){ - Utils.setField(currentElem,countField,null); - Utils.setField(data,countField,null); + if (!Utils.equalsOrNotSet(currentElem, data, TAbstractDataAttribute::isSetCount, TAbstractDataAttribute::getCount)){ + return false; } + if((getBType() == TPredefinedBasicTypeEnum.ENUM || getBType() == TPredefinedBasicTypeEnum.STRUCT) && !Objects.equals(getType(),data.getType())) { @@ -87,10 +74,9 @@ public boolean hasSameContentAs(T data) { } for(TVal prdVal : data.getVal()){ - boolean hasSameVal = currentElem.getVal().stream() - .anyMatch(rcvVal -> rcvVal.getValue().equals(prdVal.getValue()) && - Objects.equals(rcvVal.getSGroup(), prdVal.getSGroup())); - if(!hasSameVal) { + if(currentElem.isSetVal() && currentElem.getVal().stream() + .noneMatch(rcvVal -> rcvVal.getValue().equals(prdVal.getValue()) && + Utils.equalsOrNotSet(rcvVal, prdVal, TVal::isSetSGroup, TVal::getSGroup))) { return false; } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DAAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DAAdapter.java index 47ec0c7ee..55fdbb348 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DAAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DAAdapter.java @@ -6,7 +6,6 @@ import lombok.Getter; import org.lfenergy.compas.scl2007b4.model.TDA; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.dto.DaTypeName; import org.lfenergy.compas.sct.commons.exception.ScdException; @@ -29,8 +28,4 @@ public void check(DaTypeName daTypeName) throws ScdException { daTypeName.setFc(currentElem.getFc()); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DATypeAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DATypeAdapter.java index 9e2c796af..cfe8ce5e2 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DATypeAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DATypeAdapter.java @@ -7,7 +7,10 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.scl2007b4.model.TBDA; +import org.lfenergy.compas.scl2007b4.model.TDAType; +import org.lfenergy.compas.scl2007b4.model.TPredefinedBasicTypeEnum; +import org.lfenergy.compas.scl2007b4.model.TProtNs; import org.lfenergy.compas.sct.commons.dto.DaTypeName; import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate; import org.lfenergy.compas.sct.commons.exception.ScdException; @@ -243,11 +246,6 @@ public DataTypeTemplateAdapter getDataTypeTemplateAdapter() { return parentAdapter; } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public Optional getBdaAdapterByName(String name) { Optional opBda = getBDAByName(name); if(opBda.isPresent()){ @@ -270,9 +268,5 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getBDA().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOAdapter.java index 13da0257a..b07157329 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOAdapter.java @@ -5,7 +5,6 @@ package org.lfenergy.compas.sct.commons.scl.dtt; import org.lfenergy.compas.scl2007b4.model.TDO; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import java.util.Optional; @@ -29,11 +28,6 @@ public Optional getDoTypeAdapter() { return getDataTypeTemplateAdapter().getDOTypeAdapterById(currentElem.getType()); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public String getType() { return currentElem.getType(); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOTypeAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOTypeAdapter.java index 84c3a7166..e242b66a9 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOTypeAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DOTypeAdapter.java @@ -125,11 +125,6 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getDOType().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public boolean containsDAWithDAName(String da){ return currentElem.getSDOOrDA() .stream() diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapter.java index b707f104f..160b00ff2 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapter.java @@ -31,11 +31,6 @@ protected boolean amChildElementRef() { return currentElem == parentAdapter.getCurrentElem().getDataTypeTemplates(); } - @Override - protected void addPrivate(TPrivate tPrivate) { - throw new IllegalArgumentException("Private is not Allowed here"); - } - public Optional getLNodeTypeAdapterById(String id) { for(TLNodeType tlNodeType : currentElem.getLNodeType()){ if(tlNodeType.getId().equals(id)) { diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/EnumTypeAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/EnumTypeAdapter.java index 8aa1c52eb..d7464cdf1 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/EnumTypeAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/EnumTypeAdapter.java @@ -7,7 +7,6 @@ import org.lfenergy.compas.scl2007b4.model.TEnumType; import org.lfenergy.compas.scl2007b4.model.TEnumVal; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import java.util.List; import java.util.Objects; @@ -54,8 +53,4 @@ public DataTypeTemplateAdapter getDataTypeTemplateAdapter() { return parentAdapter; } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/LNodeTypeAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/LNodeTypeAdapter.java index 48c425c0d..9a55dcd0e 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/LNodeTypeAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/dtt/LNodeTypeAdapter.java @@ -10,7 +10,6 @@ import org.lfenergy.compas.scl2007b4.model.TDO; import org.lfenergy.compas.scl2007b4.model.TLNodeType; import org.lfenergy.compas.scl2007b4.model.TPredefinedBasicTypeEnum; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.dto.DaTypeName; import org.lfenergy.compas.sct.commons.dto.DoTypeName; import org.lfenergy.compas.sct.commons.dto.ResumedDataTemplate; @@ -69,11 +68,6 @@ public boolean hasSameContentAs(TLNodeType tlNodeType) { return true; } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public boolean containsDOWithDOTypeId(String doTypeId) { return currentElem.getDO().stream() .anyMatch(tdo -> tdo.getType().equals(doTypeId)); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapter.java index 1f8500b55..aa5e5ac90 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapter.java @@ -7,7 +7,6 @@ import org.lfenergy.compas.scl2007b4.model.THeader; import org.lfenergy.compas.scl2007b4.model.THitem; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; @@ -46,11 +45,6 @@ public HeaderAdapter addHistoryItem(String who, String what, String why){ return this; } - @Override - protected void addPrivate(TPrivate tPrivate) { - throw new IllegalArgumentException("Private is not Allowed here"); - } - public String getHeaderId() { return currentElem.getId(); } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java index 6b5c30754..3e4c3144e 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractDAIAdapter.java @@ -30,8 +30,9 @@ public S getDataAdapterByName(String sName) throws Scd public void setValImport(boolean b){ currentElem.setValImport(b); } + public Boolean isValImport(){ - return currentElem.isValImport(); + return currentElem.isSetValImport() ? currentElem.isValImport() : null; } public AbstractDAIAdapter update(Map daiValues) throws ScdException { @@ -46,16 +47,16 @@ public AbstractDAIAdapter update(Map } public void update(Long sGroup, String val) throws ScdException { - if(currentElem.isValImport() != null && !currentElem.isValImport()){ + if(currentElem.isSetValImport() && !currentElem.isValImport()){ String msg = String.format( "DAI(%s) cannot be updated : valImport(false)",currentElem.getName() ); throw new ScdException(msg); } - Stream tValStream = currentElem.getVal().stream() ; - if(sGroup != 0){ - Optional tVal = tValStream.filter(tValElem -> tValElem.getSGroup() != null && - tValElem.getSGroup().equals(sGroup)) + Stream tValStream = currentElem.getVal().stream(); + if (sGroup != null && sGroup != 0) { + Optional tVal = tValStream.filter(tValElem -> tValElem.isSetSGroup() && + sGroup.equals(tValElem.getSGroup())) .findFirst(); if(tVal.isPresent()){ tVal.get().setValue(val); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java index 8ce8570ce..db130bb50 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/AbstractLNAdapter.java @@ -16,7 +16,6 @@ import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter; import org.lfenergy.compas.sct.commons.scl.dtt.LNodeTypeAdapter; -import java.lang.reflect.Field; import java.util.*; import java.util.stream.Collectors; @@ -98,6 +97,10 @@ public String getLnType(){ return currentElem.getLnType(); } + public List getExtRefs() { + return getExtRefs(null); + } + public List getExtRefs(ExtRefSignalInfo filter) { if(!hasInputs()){ return new ArrayList<>(); @@ -111,10 +114,10 @@ public List getExtRefs(ExtRefSignalInfo filter) { .filter(tExtRef -> ((filter.getDesc() == null && tExtRef.getDesc().isEmpty()) || Objects.equals(filter.getDesc(),tExtRef.getDesc()) ) && - Objects.equals(filter.getPDO(),tExtRef.getPDO()) && - Objects.equals(filter.getPDA(),tExtRef.getPDA()) && - Objects.equals(filter.getIntAddr(),tExtRef.getIntAddr()) && - Objects.equals(filter.getPServT(),tExtRef.getPServT())) + Objects.equals(filter.getPDO(),tExtRef.getPDO()) && + Objects.equals(filter.getPDA(),tExtRef.getPDA()) && + Objects.equals(filter.getIntAddr(),tExtRef.getIntAddr()) && + Objects.equals(filter.getPServT(),tExtRef.getPServT())) .collect(Collectors.toList()); } @@ -136,9 +139,9 @@ public List getExtRefsBySignalInfo(ExtRefSignalInfo signalInfo) { return currentElem.getInputs().getExtRef() .stream() .filter(tExtRef -> Objects.equals(signalInfo.getDesc(), tExtRef.getDesc()) && - Objects.equals(tExtRef.getPDO(), signalInfo.getPDO()) && - Objects.equals(signalInfo.getIntAddr(), tExtRef.getIntAddr()) && - Objects.equals(signalInfo.getPServT(), tExtRef.getPServT()) + Objects.equals(tExtRef.getPDO(), signalInfo.getPDO()) && + Objects.equals(signalInfo.getIntAddr(), tExtRef.getIntAddr()) && + Objects.equals(signalInfo.getPServT(), tExtRef.getPServT()) ) .collect(Collectors.toList()); } @@ -194,20 +197,7 @@ protected void updateExtRefBindingInfo(TExtRef extRef, ExtRefInfo extRefInfo) { extRef.setPrefix(bindingInfo.getPrefix()); // invalid source info - extRef.setSrcCBName(null); - extRef.setSrcLDInst(null); - extRef.setSrcPrefix(null); - extRef.setSrcLNInst(null); - // the JAXB don't provide setter for srcLNClass - // SCL XSD doesn't accept empty srcLNClass list - // No choice here but to do reflection - try { - Field f = extRef.getClass().getDeclaredField("srcLNClass"); - f.setAccessible(true); - f.set(extRef,null); - } catch ( Exception e) { - log.error("Cannot nullify srcLNClass:", e); - } + removeExtRefSourceBinding(extRef); isSrcReset = true; } // @@ -239,12 +229,12 @@ protected List> getControlBlocks(List tDataSets, TServ tControls = this.lookUpControlBlocksByDataSetRef(tDataSet.getName(),TGSEControl.class); controlBlocks.addAll( tControls.stream() - .map(tgseControl -> { - var g = new GooseControlBlock((TGSEControl)tgseControl); - g.setMetaData(metaData); - return g; - }) - .collect(Collectors.toList()) + .map(tgseControl -> { + var g = new GooseControlBlock((TGSEControl)tgseControl); + g.setMetaData(metaData); + return g; + }) + .collect(Collectors.toList()) ); } @@ -253,12 +243,12 @@ protected List> getControlBlocks(List tDataSets, TServ tControls = this.lookUpControlBlocksByDataSetRef(tDataSet.getName(),TSampledValueControl.class); controlBlocks.addAll( tControls.stream() - .map(sampledValueControl -> { - var s = new SMVControlBlock((TSampledValueControl) sampledValueControl); - s.setMetaData(metaData); - return s; - }) - .collect(Collectors.toList()) + .map(sampledValueControl -> { + var s = new SMVControlBlock((TSampledValueControl) sampledValueControl); + s.setMetaData(metaData); + return s; + }) + .collect(Collectors.toList()) ); } @@ -266,12 +256,12 @@ protected List> getControlBlocks(List tDataSets, TServ tControls = this.lookUpControlBlocksByDataSetRef(tDataSet.getName(),TReportControl.class); controlBlocks.addAll( tControls.stream() - .map(reportControl -> { - var r = new ReportControlBlock((TReportControl) reportControl); - r.setMetaData(metaData); - return r; - }) - .collect(Collectors.toList()) + .map(reportControl -> { + var r = new ReportControlBlock((TReportControl) reportControl); + r.setMetaData(metaData); + return r; + }) + .collect(Collectors.toList()) ); } } @@ -453,11 +443,11 @@ public List getDAI(ResumedDataTemplate rDtt, boolean updata SclRootAdapter sclRootAdapter = parentAdapter.getParentAdapter().getParentAdapter(); DataTypeTemplateAdapter dttAdapter = sclRootAdapter.getDataTypeTemplateAdapter(); LNodeTypeAdapter lNodeTypeAdapter = dttAdapter.getLNodeTypeAdapterById(lnType) - .orElseThrow( - () -> new ScdException( - String.format("Corrupted SCD : lnType missing for LN : %s%s", getLNClass(),getLNInst()) - ) - ); + .orElseThrow( + () -> new ScdException( + String.format("Corrupted SCD : lnType missing for LN : %s%s", getLNClass(),getLNInst()) + ) + ); List resumedDTTs = lNodeTypeAdapter.getResumedDTTs(rDtt); resumedDTTs.forEach(this::overrideAttributesFromDAI); @@ -471,23 +461,23 @@ public List getDAI(ResumedDataTemplate rDtt, boolean updata protected void overrideAttributesFromDAI(final ResumedDataTemplate rDtt) { findMatch(rDtt.getDoName(), rDtt.getDaName()) - .map(iDataAdapter -> (AbstractDAIAdapter) iDataAdapter) - .map(AbstractDAIAdapter::getCurrentElem) - .ifPresent(tdai -> { - rDtt.setDaiValues(tdai.getVal()); - if (rDtt.getDaName().getFc() == TFCEnum.SG || rDtt.getDaName().getFc() == TFCEnum.SE) { - boolean isGroup = hasSgGroup(tdai); - if (isGroup) { - rDtt.setValImport(!Boolean.FALSE.equals(tdai.isValImport()) && iedHasConfSG()); - } else { - rDtt.setValImport(false); - log.warn("Inconsistency in the SCD file - DAI {} with fc={} must have a sGroup attribute", - rDtt.getObjRef(getCurrentIED().getName(), parentAdapter.getInst()), rDtt.getDaName().getFc()); + .map(iDataAdapter -> (AbstractDAIAdapter) iDataAdapter) + .map(AbstractDAIAdapter::getCurrentElem) + .ifPresent(tdai -> { + rDtt.setDaiValues(tdai.getVal()); + if (rDtt.getDaName().getFc() == TFCEnum.SG || rDtt.getDaName().getFc() == TFCEnum.SE) { + boolean isGroup = hasSgGroup(tdai); + if (isGroup) { + rDtt.setValImport((!tdai.isSetValImport() || tdai.isValImport()) && iedHasConfSG()); + } else { + rDtt.setValImport(false); + log.warn("Inconsistency in the SCD file - DAI {} with fc={} must have a sGroup attribute", + rDtt.getObjRef(getCurrentIED().getName(), parentAdapter.getInst()), rDtt.getDaName().getFc()); + } + } else if (tdai.isSetValImport()) { + rDtt.setValImport(tdai.isValImport()); } - } else if (tdai.isValImport() != null) { - rDtt.setValImport(tdai.isValImport()); - } - }); + }); } private boolean iedHasConfSG() { @@ -501,7 +491,7 @@ private IEDAdapter getCurrentIED() { } private boolean hasSgGroup(TDAI tdai) { - return tdai.getVal().stream().anyMatch(tVal -> tVal.getSGroup() != null && tVal.getSGroup().intValue() > 0); + return tdai.getVal().stream().anyMatch(tVal -> tVal.isSetSGroup() && tVal.getSGroup() > 0); } /** @@ -580,7 +570,7 @@ public void updateDAI(@NonNull ResumedDataTemplate rDtt) throws ScdException { } } if(daiAdapter == null){ - daiAdapter = doiOrSdoiAdapter.addDAI(daTypeName.getName(),rDtt.isUpdatable()); + daiAdapter = doiOrSdoiAdapter.addDAI(daTypeName.getName(),rDtt.isUpdatable()); } daiAdapter.update(daTypeName.getDaiValues()); @@ -619,9 +609,9 @@ public boolean matches(ObjectReference objRef) { ) ); ResumedDataTemplate filter = ResumedDataTemplate.builder() - .lnInst(getLNInst()) - .lnClass(getLNClass()) - .lnType(currentElem.getLnType()).build(); + .lnInst(getLNInst()) + .lnClass(getLNClass()) + .lnType(currentElem.getLnType()).build(); List rDtts = lNodeTypeAdapter.getResumedDTTs(filter); return matchesDataAttributes(dataAttribute) || @@ -672,8 +662,28 @@ public Map getDAIValues(ResumedDataTemplate rDtt) { } Map res = new HashMap<>(); - tVals.forEach( tVal -> res.put(tVal.getSGroup(),tVal.getValue())); + tVals.forEach( tVal -> res.put( + tVal.isSetSGroup() ? tVal.getSGroup() : 0L, tVal.getValue()) + ); return res; } + + public void removeAllControlBlocksAndDatasets() { + currentElem.unsetReportControl(); + currentElem.unsetLogControl(); + currentElem.unsetDataSet(); + } + + public void removeAllExtRefSourceBindings() { + getExtRefs().forEach(this::removeExtRefSourceBinding); + } + + private void removeExtRefSourceBinding(final TExtRef tExtRef){ + tExtRef.setSrcCBName(null); + tExtRef.setSrcLDInst(null); + tExtRef.setSrcPrefix(null); + tExtRef.setSrcLNInst(null); + tExtRef.unsetSrcLNClass(); + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java index f687df296..5e2fd381d 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapter.java @@ -4,7 +4,10 @@ package org.lfenergy.compas.sct.commons.scl.ied; -import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.scl2007b4.model.TAnyLN; +import org.lfenergy.compas.scl2007b4.model.TDAI; +import org.lfenergy.compas.scl2007b4.model.TDOI; +import org.lfenergy.compas.scl2007b4.model.TSDI; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -36,11 +39,6 @@ public RootSDIAdapter getStructuredDataAdapterByName(String sName) throws ScdExc ); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - @Override public DAIAdapter getDataAdapterByName(String daName) throws ScdException { return currentElem.getSDIOrDAI() @@ -85,9 +83,5 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getSDIOrDAI().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java index 1d79e330a..ba9651a8d 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapter.java @@ -128,11 +128,6 @@ public boolean findAccessPointByName(String apName) { .anyMatch(tAccessPoint -> tAccessPoint.getName().equals(apName)); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public List getExtRefBinders(@NonNull ExtRefSignalInfo signalInfo) throws ScdException { if(!signalInfo.isValid()){ throw new ScdException("Invalid ExtRef signal (pDO,pDA or intAddr))"); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java index fdfbf6f89..780e983a0 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LDeviceAdapter.java @@ -9,7 +9,6 @@ import org.apache.commons.lang3.StringUtils; import org.lfenergy.compas.scl2007b4.model.TLDevice; import org.lfenergy.compas.scl2007b4.model.TLLN0Enum; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.dto.*; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -145,8 +144,4 @@ public Set getDAI(ResumedDataTemplate rDtt, boolean updatab } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java index a269255d2..de6bebe65 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LN0Adapter.java @@ -7,7 +7,6 @@ import org.lfenergy.compas.scl2007b4.model.LN0; import org.lfenergy.compas.scl2007b4.model.TLLN0Enum; -import org.lfenergy.compas.scl2007b4.model.TPrivate; public class LN0Adapter extends AbstractLNAdapter { @@ -40,15 +39,17 @@ public String getPrefix() { return ""; } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - @Override protected boolean matchesDataAttributes(String dataAttribute){ return super.matchesDataAttributes(dataAttribute) || currentElem.getSampledValueControl().stream().anyMatch(smp -> smp.getName().equals(dataAttribute)) || currentElem.getGSEControl().stream().anyMatch(gse -> gse.getName().equals(dataAttribute)); } + + @Override + public void removeAllControlBlocksAndDatasets() { + super.removeAllControlBlocksAndDatasets(); + currentElem.unsetGSEControl(); + currentElem.unsetSampledValueControl(); + } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LNAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LNAdapter.java index 9092eef7a..f281540a5 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LNAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/LNAdapter.java @@ -3,8 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 package org.lfenergy.compas.sct.commons.scl.ied; + import org.lfenergy.compas.scl2007b4.model.TLN; -import org.lfenergy.compas.scl2007b4.model.TPrivate; public class LNAdapter extends AbstractLNAdapter{ @@ -27,11 +27,6 @@ public String getLNClass() { return null; } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - @Override public String getLNInst() { return currentElem.getInst(); diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/RootSDIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/RootSDIAdapter.java index 61591dd34..39f04e794 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/RootSDIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/RootSDIAdapter.java @@ -5,7 +5,6 @@ package org.lfenergy.compas.sct.commons.scl.ied; import org.lfenergy.compas.scl2007b4.model.TDAI; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.scl2007b4.model.TSDI; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -66,11 +65,6 @@ public IDataParentAdapter addSDOI(String sdoName) { return new SDIAdapter(this,tsdi); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public static class DAIAdapter extends AbstractDAIAdapter { public DAIAdapter(RootSDIAdapter rootSDIAdapter, TDAI tdai) { @@ -82,9 +76,5 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getSDIOrDAI().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/SDIAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/SDIAdapter.java index 0dc215132..245cb1dba 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/SDIAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/ied/SDIAdapter.java @@ -5,7 +5,6 @@ package org.lfenergy.compas.sct.commons.scl.ied; import org.lfenergy.compas.scl2007b4.model.TDAI; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.scl2007b4.model.TSDI; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; @@ -76,11 +75,6 @@ public SDIAdapter addSDOI(String sdoName) { return new SDIAdapter(this,tsdi); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } - public static class DAIAdapter extends AbstractDAIAdapter { protected DAIAdapter(SDIAdapter parentAdapter, TDAI currentElem) { @@ -92,9 +86,5 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getSDIOrDAI().contains(currentElem); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); - } } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapter.java index 21737c0ae..7c178bc49 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapter.java @@ -4,9 +4,11 @@ package org.lfenergy.compas.sct.commons.scl.sstation; import org.lfenergy.compas.scl2007b4.model.TBay; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; + +import java.util.stream.Stream; public class BayAdapter extends SclElementAdapter { @@ -32,7 +34,14 @@ protected boolean amChildElementRef() { } @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); + protected String elementXPath() { + return String.format("Bay[%s]", Utils.xpathAttributeFilter("name", currentElem.isSetName() ? currentElem.getName() : null)); + } + + public Stream streamFunctionAdapters(){ + if (!currentElem.isSetFunction()){ + return Stream.empty(); + } + return currentElem.getFunction().stream().map(tFunction -> new FunctionAdapter(this, tFunction)); } } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/FunctionAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/FunctionAdapter.java new file mode 100644 index 000000000..c2062ea26 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/FunctionAdapter.java @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2021 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.sct.commons.scl.sstation; + +import org.apache.commons.lang3.StringUtils; +import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader; +import org.lfenergy.compas.scl2007b4.model.TFunction; +import org.lfenergy.compas.scl2007b4.model.TLNode; +import org.lfenergy.compas.scl2007b4.model.TPrivate; +import org.lfenergy.compas.sct.commons.exception.ScdException; +import org.lfenergy.compas.sct.commons.scl.PrivateService; +import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; + +import java.util.List; +import java.util.ListIterator; +import java.util.stream.Collectors; + +import static org.lfenergy.compas.sct.commons.util.PrivateEnum.COMPAS_ICDHEADER; + +public class FunctionAdapter extends SclElementAdapter { + + public FunctionAdapter(BayAdapter parentAdapter, TFunction currentElem) { + super(parentAdapter, currentElem); + } + + @Override + protected boolean amChildElementRef() { + return parentAdapter.getCurrentElem().getFunction().contains(currentElem); + } + + @Override + protected String elementXPath() { + return String.format("Function[%s]", Utils.xpathAttributeFilter("name", currentElem.isSetName() ? currentElem.getName() : null)); + } + + public void updateLNodeIedNames() throws ScdException { + if (!currentElem.isSetLNode()) { + return; + } + // use ListIterator to add & remove items in place + ListIterator lNodeIterator = currentElem.getLNode().listIterator(); + while (lNodeIterator.hasNext()) { + TLNode lNode = lNodeIterator.next(); + List icdHeaders = PrivateService.getCompasPrivates(lNode, TCompasICDHeader.class); + if (icdHeaders.isEmpty()){ + throw new ScdException(getXPath() + " doesn't contain any Private/compas:ICDHeader"); + } + if (icdHeaders.size() == 1) { + setLNodeIedName(lNode, icdHeaders.get(0).getIEDName()); + } else { + lNodeIterator.remove(); + PrivateService.removePrivates(lNode, COMPAS_ICDHEADER); + List newLNodes = distributeIcdHeaders(lNode, icdHeaders); + newLNodes.forEach(lNodeIterator::add); + } + } + } + + private List distributeIcdHeaders(TLNode lNode, List compasICDHeaders) { + LNodeAdapter lNodeAdapter = new LNodeAdapter(null, lNode); + return compasICDHeaders.stream().map(compasICDHeader -> { + TPrivate icdHeaderPrivate = PrivateService.createPrivate(compasICDHeader); + TLNode newLNode = lNodeAdapter.deepCopy(); + newLNode.getPrivate().add(icdHeaderPrivate); + setLNodeIedName(newLNode, compasICDHeader.getIEDName()); + return newLNode; + }).collect(Collectors.toList()); + } + + private void setLNodeIedName(TLNode lNode, String privateIedName) { + if (StringUtils.isBlank(privateIedName)){ + LNodeAdapter lNodeAdapter = new LNodeAdapter(null, lNode); + throw new ScdException(getXPath() + lNodeAdapter.getXPath() + "/Private/compas:ICDHeader/@IEDName is missing or is blank"); + } + lNode.setIedName(privateIedName); + } +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/LNodeAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/LNodeAdapter.java new file mode 100644 index 000000000..51fec68b9 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/LNodeAdapter.java @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl.sstation; + +import org.lfenergy.compas.scl2007b4.model.TFunction; +import org.lfenergy.compas.scl2007b4.model.TLNode; +import org.lfenergy.compas.scl2007b4.model.TText; +import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; + +public class LNodeAdapter extends SclElementAdapter { + + public LNodeAdapter(FunctionAdapter parentAdapter, TLNode currentElem) { + super(parentAdapter, currentElem); + } + + @Override + protected boolean amChildElementRef() { + TFunction parentElem = parentAdapter.getCurrentElem(); + return parentElem.isSetLNode() && parentElem.getLNode().contains(this.currentElem); + } + + public TLNode deepCopy() { + TLNode newLNode = new TLNode(); + newLNode.setDesc(currentElem.getDesc()); + newLNode.setIedName(currentElem.getIedName()); + newLNode.setLdInst(currentElem.getLdInst()); + newLNode.setLnInst(currentElem.getLnInst()); + newLNode.setLnType(currentElem.getLnType()); + newLNode.setPrefix(currentElem.getPrefix()); + if (currentElem.isSetText()) { + TText newText = new TText(); + newText.setSource(currentElem.getText().getSource()); + newText.getContent().addAll(currentElem.getText().getContent()); + newText.getOtherAttributes().putAll(currentElem.getText().getOtherAttributes()); + newLNode.setText(newText); + } + if (currentElem.isSetPrivate()) { + newLNode.getPrivate().addAll(currentElem.getPrivate()); + } + if (currentElem.isSetLnClass()) { + newLNode.getLnClass().addAll(currentElem.getLnClass()); + } + if (currentElem.isSetAny()) { + newLNode.getAny().addAll(currentElem.getAny()); + } + newLNode.getOtherAttributes().putAll(currentElem.getOtherAttributes()); + return newLNode; + } + + @Override + protected String elementXPath() { + return String.format("LNode[%s and %s and %s and %s and %s]", + Utils.xpathAttributeFilter("iedName", currentElem.isSetIedName() ? currentElem.getIedName() : null), + Utils.xpathAttributeFilter("ldInst", currentElem.isSetLdInst() ? currentElem.getLdInst() : null), + Utils.xpathAttributeFilter("Prefix", currentElem.isSetPrefix() ? currentElem.getPrefix() : null), + Utils.xpathAttributeFilter("lnClass", currentElem.isSetLnClass() ? currentElem.getLnClass() : null), + Utils.xpathAttributeFilter("lnInst", currentElem.isSetLnInst() ? currentElem.getLnInst() : null) + ); + } + +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/SubstationAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/SubstationAdapter.java index 605b4df9f..6b1e34200 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/SubstationAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/SubstationAdapter.java @@ -4,13 +4,14 @@ package org.lfenergy.compas.sct.commons.scl.sstation; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.scl2007b4.model.TSubstation; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; import java.util.Optional; +import java.util.stream.Stream; public class SubstationAdapter extends SclElementAdapter { @@ -37,6 +38,11 @@ protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getSubstation().contains(currentElem); } + @Override + protected String elementXPath() { + return String.format("Substation[%s]", Utils.xpathAttributeFilter("name", currentElem.isSetName() ? currentElem.getName() : null)); + } + public Optional getVoltageLevelAdapter(String vLevelName) { return currentElem.getVoltageLevel() .stream() @@ -45,8 +51,11 @@ public Optional getVoltageLevelAdapter(String vLevelName) { .findFirst(); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); + public Stream streamVoltageLevelAdapters() { + if (!currentElem.isSetVoltageLevel()){ + return Stream.empty(); + } + return currentElem.getVoltageLevel().stream().map(tVoltageLevel -> new VoltageLevelAdapter(this, tVoltageLevel)); } + } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/VoltageLevelAdapter.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/VoltageLevelAdapter.java index 96b035566..de7408704 100644 --- a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/VoltageLevelAdapter.java +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/scl/sstation/VoltageLevelAdapter.java @@ -3,12 +3,13 @@ // SPDX-License-Identifier: Apache-2.0 package org.lfenergy.compas.sct.commons.scl.sstation; -import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.scl2007b4.model.TVoltageLevel; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclElementAdapter; +import org.lfenergy.compas.sct.commons.util.Utils; import java.util.Optional; +import java.util.stream.Stream; public class VoltageLevelAdapter extends SclElementAdapter { @@ -28,12 +29,16 @@ public VoltageLevelAdapter(SubstationAdapter parentAdapter, String vLevelName) t setCurrentElem(tVoltageLevel); } - @Override protected boolean amChildElementRef() { return parentAdapter.getCurrentElem().getVoltageLevel().contains(currentElem); } + @Override + protected String elementXPath() { + return String.format("VoltageLevel[%s]", Utils.xpathAttributeFilter("name", currentElem.isSetName() ? currentElem.getName() : null)); + } + public Optional getBayAdapter(String bayName) { return currentElem.getBay() .stream() @@ -42,8 +47,11 @@ public Optional getBayAdapter(String bayName) { .findFirst(); } - @Override - protected void addPrivate(TPrivate tPrivate) { - currentElem.getPrivate().add(tPrivate); + public Stream streamBayAdapters() { + if (!currentElem.isSetBay()){ + return Stream.empty(); + } + return currentElem.getBay().stream().map(tBay -> new BayAdapter(this, tBay)); } + } diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java new file mode 100644 index 000000000..752d71b0f --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/CommonConstants.java @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +public final class CommonConstants { + + public static final String ICD_SYSTEM_VERSION_UUID = "ICDSystemVersionUUID"; + public static final String IED_NAME = "IEDName"; + public static final String HEADER_ID = "headerId"; + public static final String HEADER_VERSION = "headerVersion"; + public static final String HEADER_REVISION = "headerRevision"; + + private CommonConstants() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/PrivateEnum.java b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/PrivateEnum.java new file mode 100644 index 000000000..b9a1f8fa5 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/PrivateEnum.java @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import lombok.Getter; +import org.lfenergy.compas.scl2007b4.model.*; + +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.stream.Collectors; + +public enum PrivateEnum { + + COMPAS_BAY("COMPAS-Bay", TCompasBay.class), + COMPAS_CRITERIA("COMPAS-Criteria", TCompasCriteria.class), + COMPAS_FLOW("COMPAS-Flow", TCompasFlow.class), + COMPAS_FUNCTION("COMPAS-Function", TCompasFunction.class), + COMPAS_ICDHEADER("COMPAS-ICDHeader", TCompasICDHeader.class), + COMPAS_LDEVICE("COMPAS-LDevice", TCompasLDevice.class), + COMPAS_SCL_FILE_TYPE("COMPAS-SclFileType", TCompasSclFileType.class), + COMPAS_SYSTEM_VERSION("COMPAS-SystemVersion", TCompasSystemVersion.class); + + private static final Map, PrivateEnum> classToEnum = Arrays.stream(PrivateEnum.values()).collect(Collectors.toMap( + compasPrivateEnum -> compasPrivateEnum.compasClass, + Function.identity())); + + @Getter + private final String privateType; + @Getter + private final Class compasClass; + + PrivateEnum(String privateType, Class compasClass) { + this.privateType = privateType; + this.compasClass = compasClass; + } + + @NotNull + public static PrivateEnum fromClass(Class compasClass) { + PrivateEnum result = classToEnum.get(compasClass); + if (result == null) { + throw new NoSuchElementException(String.format("Class %s is not mapped to a compas type. See %s", compasClass.getName(), + PrivateEnum.class.getName())); + } + return result; + } + + @Override + public String toString() { + return privateType; + } + +} 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 new file mode 100644 index 000000000..cb84ae828 --- /dev/null +++ b/sct-commons/src/main/java/org/lfenergy/compas/sct/commons/util/Utils.java @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@Slf4j +public final class Utils { + + public static final String LEAVING_PREFIX = "<<< Leaving: ::"; + public static final String ENTERING_PREFIX = ">>> Entering: ::"; + + private Utils() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + public static String entering() { + return ENTERING_PREFIX + + getMethodName(); + } + + public static String leaving(Long startTime) { + if (startTime == null || startTime <= 0) { + return LEAVING_PREFIX + + getMethodName(); + } + return LEAVING_PREFIX + + getMethodName() + + " - Timer duration: " + + (System.nanoTime() - startTime) / Math.pow(10, 9) + + " sec."; + } + + private static String getMethodName() { + try { + return (new Throwable()).getStackTrace()[2].getMethodName(); + } catch (Exception e) { + return "-"; + } + } + + public static String leaving() { + return LEAVING_PREFIX + + getMethodName(); + } + + /** + * Test if two fields with primitive values are equals or are both not set. + * @param o1 object to compare + * @param o2 object to compare + * @param isSet predicate that returns if fields is set + * @param getValue getter that return the unboxed field + * @return true if both fields are set and are equals, or if both fields are not set. False otherwise. + */ + public static boolean equalsOrNotSet(T o1, T o2, Predicate isSet, Function getValue) { + Objects.requireNonNull(o1); + Objects.requireNonNull(o2); + if (!isSet.test(o1)){ + return !isSet.test(o2); + } + if (!isSet.test(o2)){ + return false; + } + return Objects.equals(getValue.apply(o1), getValue.apply(o2)); + } + + public static String xpathAttributeFilter(String name, String value) { + if (value == null){ + return String.format("not(@%s)", name); + } else { + return String.format("@%s=\"%s\"", name, value); + } + } + + public static String xpathAttributeFilter(String name, Collection value) { + if (value == null || value.isEmpty() || value.stream().allMatch(Objects::isNull)){ + return String.format("not(@%s)", name); + } else { + return xpathAttributeFilter(name, value.stream().filter(Objects::nonNull).collect(Collectors.joining(" "))); + } + } +} diff --git a/sct-commons/src/main/resources/binding_configuration.xjb b/sct-commons/src/main/resources/binding_configuration.xjb new file mode 100644 index 000000000..6ecd6bf93 --- /dev/null +++ b/sct-commons/src/main/resources/binding_configuration.xjb @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/CommonConstantsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/CommonConstantsTest.java deleted file mode 100644 index c2708084e..000000000 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/CommonConstantsTest.java +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2021 RTE FRANCE -// -// SPDX-License-Identifier: Apache-2.0 - -package org.lfenergy.compas.sct.commons; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - - -class CommonConstantsTest { - @Test - void testShouldReturnNOKWhenConstructClassCauseForbidden() { - assertThrows(UnsupportedOperationException.class, CommonConstants::new); - } - -} \ No newline at end of file diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/PrivateServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/PrivateServiceTest.java new file mode 100644 index 000000000..e3213f04d --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/PrivateServiceTest.java @@ -0,0 +1,253 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.platform.commons.support.ReflectionSupport; +import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.sct.commons.exception.ScdException; +import org.lfenergy.compas.sct.commons.util.PrivateEnum; + +import javax.xml.bind.JAXBElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class PrivateServiceTest { + + private TPrivate privateSCD; + private TPrivate privateICD; + private ObjectFactory objectFactory; + + @BeforeEach + void setUp() { + objectFactory = new ObjectFactory(); + privateSCD = objectFactory.createTPrivate(); + privateSCD.setType(PrivateEnum.COMPAS_SCL_FILE_TYPE.getPrivateType()); + privateSCD.getContent().add(objectFactory.createSclFileType(TCompasSclFileType.SCD)); + privateICD = objectFactory.createTPrivate(); + privateICD.setType(PrivateEnum.COMPAS_SCL_FILE_TYPE.getPrivateType()); + privateICD.getContent().add(objectFactory.createSclFileType(TCompasSclFileType.ICD)); + } + + @Test + void class_should_not_be_instantiable() { + // Given + Constructor[] constructors = PrivateService.class.getDeclaredConstructors(); + assertThat(constructors).hasSize(1); + Constructor constructor = constructors[0]; + constructor.setAccessible(true); + // When & Then + assertThatThrownBy(constructor::newInstance) + .isInstanceOf(InvocationTargetException.class) + .getCause().isInstanceOf(UnsupportedOperationException.class); + } + + @Test + void getCompasPrivates_should_return_privates_value() { + // Given : setUp + // When + List result = PrivateService.getCompasPrivates(List.of(privateSCD, privateICD), + TCompasSclFileType.class); + //Then + assertThat(result) + .hasSize(2) + .containsExactly(TCompasSclFileType.SCD, TCompasSclFileType.ICD); + } + + @Test + void getCompasPrivates_when_no_privates_match_class_should_return_empty_list() { + // Given : setUp + // When + List result = PrivateService.getCompasPrivates(List.of(privateSCD), TCompasICDHeader.class); + //Then + assertThat(result).isEmpty(); + } + + @Test + void getCompasPrivates_when_class_is_not_compas_class_should_throw_exception() { + // Given : setUp + List privates = List.of(privateSCD); + // When & Then + assertThatThrownBy(() -> PrivateService.getCompasPrivates(privates, Object.class)).isInstanceOf( + NoSuchElementException.class); + } + + @Test + void getCompasPrivates_when_content_not_match_private_type_should_throw_exception() { + // Given : setUp + privateSCD.setType(PrivateEnum.COMPAS_BAY.getPrivateType()); + Class compasClass = PrivateEnum.COMPAS_BAY.getCompasClass(); + List privates = List.of(privateSCD); + // When & Then + assertThatThrownBy(() -> PrivateService.getCompasPrivates(privates, compasClass)).isInstanceOf( + ScdException.class); + } + + @Test + void getCompasPrivates_on_base_element_should_return_privates_value() { + // Given : setUp + TBaseElement baseElement = new SCL(); + baseElement.getPrivate().add(privateSCD); + baseElement.getPrivate().add(privateICD); + // When + List result = PrivateService.getCompasPrivates(baseElement, TCompasSclFileType.class); + // Then + assertThat(result) + .hasSize(2) + .containsExactly(TCompasSclFileType.SCD, TCompasSclFileType.ICD); + } + + @Test + void getCompasPrivates_on_base_element_should_not_set_private() { + // Given + TBaseElement baseElement = new SCL(); + // When + PrivateService.getCompasPrivates(baseElement, TCompasSclFileType.class); + // Then + assertThat(baseElement.isSetPrivate()).isFalse(); + } + + @Test + void getCompasPrivate_should_return_private_value() { + // Given : setUp + // When + Optional result = PrivateService.getCompasPrivate(privateSCD, + TCompasSclFileType.class); + //Then + assertThat(result).isPresent() + .hasValue(TCompasSclFileType.SCD); + } + + @Test + void getCompasPrivate_should_return_empty() { + // Given : setUp + // When + Optional result = PrivateService.getCompasPrivate(privateSCD, + TCompasBay.class); + //Then + assertThat(result).isNotPresent(); + } + + @Test + void getCompasPrivate_should_throw_exception() { + // Given : setUp + privateSCD.getContent().add(objectFactory.createSclFileType(TCompasSclFileType.ICD)); + Class compasClass = PrivateEnum.COMPAS_SCL_FILE_TYPE.getCompasClass(); + // When & Then + assertThatThrownBy(() -> PrivateService.getCompasPrivate(privateSCD, compasClass)).isInstanceOf( + ScdException.class); + } + + @Test + void getCompasICDHeader_should_return_private_value() { + // Given + privateSCD = objectFactory.createTPrivate(); + privateSCD.setType(PrivateEnum.COMPAS_ICDHEADER.getPrivateType()); + TCompasICDHeader tCompasICDHeader = objectFactory.createTCompasICDHeader(); + privateSCD.getContent().add(objectFactory.createICDHeader(tCompasICDHeader)); + // When + Optional optionalResult = PrivateService.getCompasICDHeader(privateSCD); + //Then + assertThat(optionalResult).isPresent().get().matches(result -> result == tCompasICDHeader); + } + + @ParameterizedTest + @MethodSource("createPrivateTestSources") + void createPrivate_should_return_private_new_private(Object compasElement) throws InvocationTargetException, IllegalAccessException { + // Given + PrivateEnum privateEnum = PrivateEnum.fromClass(compasElement.getClass()); + assertThat(privateEnum).isNotNull(); + Optional optionalCreatePrivateMethod = ReflectionSupport.findMethod(PrivateService.class, "createPrivate", compasElement.getClass()); + assertThat(optionalCreatePrivateMethod).isPresent(); + Method createPrivateMethod = optionalCreatePrivateMethod.get(); + // When + Object result = createPrivateMethod.invoke(null, compasElement); + //Then + assertThat(result).isInstanceOf(TPrivate.class); + TPrivate resultPrivate = (TPrivate) result; + assertThat(resultPrivate).isNotNull() + .hasFieldOrPropertyWithValue("type", privateEnum.getPrivateType()); + assertThat(resultPrivate.getContent()).hasSize(1).first().satisfies(content -> assertThat(content).isInstanceOf(JAXBElement.class)); + JAXBElement content = (JAXBElement) resultPrivate.getContent().get(0); + assertThat(content.isNil()).isFalse(); + assertThat(content.getValue()).isNotNull().isInstanceOf(compasElement.getClass()) + .isEqualTo(compasElement); + } + + public static Stream createPrivateTestSources() { + return Stream.of(new TCompasBay(), + new TCompasCriteria(), + new TCompasFlow(), + new TCompasFunction(), + new TCompasICDHeader(), + new TCompasLDevice(), + TCompasSclFileType.SCD, + new TCompasSystemVersion()); + } + + @Test + void removePrivates_should_remove_privates() { + // Given : setUp + TBaseElement baseElement = new SCL(); + baseElement.getPrivate().add(privateSCD); + // When + PrivateService.removePrivates(baseElement, PrivateEnum.COMPAS_SCL_FILE_TYPE); + // Then + assertThat(baseElement.isSetPrivate()).isFalse(); + } + + @Test + void removePrivates_should_do_nothing_when_no_private_match_type() { + // Given : setUp + TBaseElement baseElement = new SCL(); + baseElement.getPrivate().add(privateSCD); + // When + PrivateService.removePrivates(baseElement, PrivateEnum.COMPAS_ICDHEADER); + // Then + assertThat(baseElement.getPrivate()).hasSize(1); + } + + @Test + void removePrivates_should_remove_privates_of_given_type() { + // Given : setUp + TBaseElement baseElement = new SCL(); + baseElement.getPrivate().add(privateSCD); + TCompasICDHeader tCompasICDHeader = objectFactory.createTCompasICDHeader(); + baseElement.getPrivate().add(PrivateService.createPrivate(tCompasICDHeader)); + // When + PrivateService.removePrivates(baseElement, PrivateEnum.COMPAS_ICDHEADER); + // Then + assertThat(baseElement.getPrivate()).hasSize(1); + TPrivate tPrivate = baseElement.getPrivate().get(0); + assertThat(tPrivate.getType()).isEqualTo(privateSCD.getType()); + assertThat(tPrivate.getContent()).hasSize(1).first().isInstanceOf(JAXBElement.class); + JAXBElement jaxbElement = (JAXBElement) tPrivate.getContent().get(0); + assertThat(jaxbElement.isNil()).isFalse(); + assertThat(jaxbElement.getValue()).isEqualTo(TCompasSclFileType.SCD); + } + + @Test + void removePrivates_should_not_set_private() { + // Given : setUp + TBaseElement baseElement = new SCL(); + baseElement.unsetPrivate(); + // When + PrivateService.removePrivates(baseElement, PrivateEnum.COMPAS_ICDHEADER); + // Then + assertThat(baseElement.isSetPrivate()).isFalse(); + } + +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapterTest.java index c35d252e1..f83ab071b 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclRootAdapterTest.java @@ -9,12 +9,12 @@ import org.lfenergy.compas.scl2007b4.model.SCL; import org.lfenergy.compas.scl2007b4.model.TPrivate; import org.lfenergy.compas.sct.commons.exception.ScdException; -import org.lfenergy.compas.sct.commons.testhelpers.MarshallerWrapper; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; @Slf4j class SclRootAdapterTest { @@ -34,6 +34,7 @@ void testConstruction() { assertEquals(SclRootAdapter.RELEASE,sclRootAdapter.get().getSclRelease()); assertEquals(SclRootAdapter.VERSION,sclRootAdapter.get().getSclVersion()); assertEquals(SclRootAdapter.REVISION,sclRootAdapter.get().getSclRevision()); + assertIsMarshallable(sclRootAdapter.get().getCurrentElem()); assertThrows(IllegalArgumentException.class, () -> new SclRootAdapter(new SCL())); } @@ -50,10 +51,7 @@ void addIED() throws Exception { assertDoesNotThrow(() -> sclRootAdapter.addIED(icd1, "IED_NAME1")); assertThrows(ScdException.class, () -> sclRootAdapter.addIED(icd1, "IED_NAME1")); assertDoesNotThrow(() -> sclRootAdapter.addIED(icd2, "IED_NAME2")); - - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - System.out.println(marshallerWrapper.marshall(sclRootAdapter.getCurrentElem())); - + assertIsMarshallable(scd); } @Test @@ -66,5 +64,6 @@ void addPrivate() throws Exception { assertTrue(sclRootAdapter.getCurrentElem().getPrivate().isEmpty()); sclRootAdapter.addPrivate(tPrivate); assertEquals(1, sclRootAdapter.getCurrentElem().getPrivate().size()); + assertIsMarshallable(scd); } -} \ No newline at end of file +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java index c068214f5..571891ae9 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SclServiceTest.java @@ -6,16 +6,10 @@ import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.lfenergy.compas.scl2007b4.model.*; -import org.lfenergy.compas.sct.commons.CommonConstants; import org.lfenergy.compas.sct.commons.dto.*; import org.lfenergy.compas.sct.commons.exception.ScdException; -import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter; -import org.lfenergy.compas.sct.commons.scl.ied.LN0Adapter; -import org.lfenergy.compas.sct.commons.testhelpers.MarshallerWrapper; +import org.lfenergy.compas.sct.commons.scl.ied.*; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; import java.util.*; @@ -25,6 +19,8 @@ import static org.junit.jupiter.api.Assertions.*; import static org.lfenergy.compas.sct.commons.testhelpers.DataTypeUtils.createDa; import static org.lfenergy.compas.sct.commons.testhelpers.DataTypeUtils.createDo; +import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; +import static org.lfenergy.compas.sct.commons.util.PrivateEnum.COMPAS_SCL_FILE_TYPE; class SclServiceTest { @@ -45,6 +41,7 @@ void testAddHistoryItem() throws ScdException { assertEquals("why", tHitem.getWhy()); assertEquals(SclRootAdapter.REVISION, tHitem.getRevision()); assertEquals(SclRootAdapter.VERSION, tHitem.getVersion()); + assertIsMarshallable(scd); } @Test @@ -59,8 +56,7 @@ void testAddIED() throws Exception { assertEquals("IED_NAME1", iedAdapter.getName()); assertNotNull(sclRootAdapter.getCurrentElem().getDataTypeTemplates()); - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - System.out.println(marshallerWrapper.marshall(scd)); + assertIsMarshallable(scd); } @Test @@ -81,8 +77,7 @@ void testAddSubnetworks() throws Exception { subNetworkDTO.addConnectedAP(connectedApDTO); assertDoesNotThrow(() -> SclService.addSubnetworks(scd, Set.of(subNetworkDTO), Optional.of(icd)).get()); - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - System.out.println(marshallerWrapper.marshall(scd)); + assertIsMarshallable(scd); } @Test @@ -95,8 +90,7 @@ void testAddSubnetworksWithoutCommunicationTagInIcd() throws Exception { assertDoesNotThrow(() -> SclService.addIED(scd, "IED_NAME1", icd)); assertDoesNotThrow(() -> SclService.addSubnetworks(scd, new HashSet<>(), Optional.of(icd))); - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - String marshalledScd = marshallerWrapper.marshall(scd); + String marshalledScd = assertIsMarshallable(scd); assertThat(marshalledScd).doesNotContain(" subNetworkDTOSet = new HashSet<>(SclService.getSubnetwork(icd)); assertDoesNotThrow(() -> SclService.addSubnetworks(scd, subNetworkDTOSet, Optional.of(icd)).get()); - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - String marshalledScd = marshallerWrapper.marshall(scd); + String marshalledScd = assertIsMarshallable(scd); assertThat(marshalledScd).contains("
", "PhysConn"); } @@ -129,8 +122,7 @@ void testAddSubnetworksWithoutImportingIcdAddressAndPhysConn() throws Exception Set subNetworkDTOSet = new HashSet<>(SclService.getSubnetwork(icd)); assertDoesNotThrow(() -> SclService.addSubnetworks(scd, subNetworkDTOSet, Optional.empty()).get()); - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - String marshalledScd = marshallerWrapper.marshall(scd); + String marshalledScd = assertIsMarshallable(scd); assertThat(marshalledScd).doesNotContain("
", "PhysConn"); } @@ -242,6 +234,7 @@ void testUpdateExtRefBinders() throws Exception { ScdException.class, () -> SclService.updateExtRefBinders(scd, extRefInfo) ); + assertIsMarshallable(scd); } @Test @@ -374,21 +367,21 @@ void getDAI_should_aggregate_attribute_from_DAI() throws Exception { ResumedDataTemplate lln0DoB = lln0.toBuilder().doName(createDo("DoB", TPredefinedCDCEnum.ACD)).build(); assertThat(dais).containsExactlyInAnyOrder( - lln0DoA.toBuilder().daName(createDa("daNotInDai", TFCEnum.CF, false, Map.of(0L, "0"))).build(), - lln0DoA.toBuilder().daName(createDa("daNotInDai2", TFCEnum.CF, true, Map.of())).build(), - lln0DoA.toBuilder().daName(createDa("daiOverrideVal", TFCEnum.CF, false, Map.of(0L, "1"))).build(), - lln0DoA.toBuilder().daName(createDa("daiOverrideValImport", TFCEnum.CF, true, Map.of())).build(), - lln0DoA.toBuilder().daName(createDa("daiOverrideValImport2", TFCEnum.CF, false, Map.of())).build(), - - lln0DoB.toBuilder().daName(createDa("structDa.daNotInDai", TFCEnum.ST, false, Map.of(0L, "0"))).build(), - lln0DoB.toBuilder().daName(createDa("structDa.daNotInDai2", TFCEnum.ST, true, Map.of())).build(), - lln0DoB.toBuilder().daName(createDa("structDa.daiOverrideVal", TFCEnum.ST, false, Map.of(0L, "1"))).build(), - lln0DoB.toBuilder().daName(createDa("structDa.daiOverrideValImport", TFCEnum.ST, true, Map.of())).build(), - lln0DoB.toBuilder().daName(createDa("structDa.daiOverrideValImport2", TFCEnum.ST, false, Map.of())).build(), - - ResumedDataTemplate.builder().prefix("").lnType("lntype2").lnClass("LPHD").lnInst("0") - .doName(createDo("PhyNam", TPredefinedCDCEnum.DPS)) - .daName(createDa("aDa", TFCEnum.BL, false, Map.of())).build() + lln0DoA.toBuilder().daName(createDa("daNotInDai", TFCEnum.CF, false, Map.of(0L, "0"))).build(), + lln0DoA.toBuilder().daName(createDa("daNotInDai2", TFCEnum.CF, true, Map.of())).build(), + lln0DoA.toBuilder().daName(createDa("daiOverrideVal", TFCEnum.CF, false, Map.of(0L, "1"))).build(), + lln0DoA.toBuilder().daName(createDa("daiOverrideValImport", TFCEnum.CF, true, Map.of())).build(), + lln0DoA.toBuilder().daName(createDa("daiOverrideValImport2", TFCEnum.CF, false, Map.of())).build(), + + lln0DoB.toBuilder().daName(createDa("structDa.daNotInDai", TFCEnum.ST, false, Map.of(0L, "0"))).build(), + lln0DoB.toBuilder().daName(createDa("structDa.daNotInDai2", TFCEnum.ST, true, Map.of())).build(), + lln0DoB.toBuilder().daName(createDa("structDa.daiOverrideVal", TFCEnum.ST, false, Map.of(0L, "1"))).build(), + lln0DoB.toBuilder().daName(createDa("structDa.daiOverrideValImport", TFCEnum.ST, true, Map.of())).build(), + lln0DoB.toBuilder().daName(createDa("structDa.daiOverrideValImport2", TFCEnum.ST, false, Map.of())).build(), + + ResumedDataTemplate.builder().prefix("").lnType("lntype2").lnClass("LPHD").lnInst("0") + .doName(createDo("PhyNam", TPredefinedCDCEnum.DPS)) + .daName(createDa("aDa", TFCEnum.BL, false, Map.of())).build() ); } @@ -399,7 +392,7 @@ void getDAI_when_LDevice_not_found_should_throw_exception() throws Exception { // when & then assertThrows(ScdException.class, - () -> SclService.getDAI(scd, "IED_NAME1", "UNKNOWNLD", new ResumedDataTemplate(), true)); + () -> SclService.getDAI(scd, "IED_NAME1", "UNKNOWNLD", new ResumedDataTemplate(), true)); } @Test @@ -413,24 +406,24 @@ void getDAI_should_filter_updatable_DA() throws Exception { // then assertThat(dais).isNotNull(); List resultSimpleDa = dais.stream() - .filter(rdtt -> rdtt.getBdaNames().isEmpty()) // test only simple DA - .map(ResumedDataTemplate::getLNRef).collect(Collectors.toList()); + .filter(rdtt -> rdtt.getBdaNames().isEmpty()) // test only simple DA + .map(ResumedDataTemplate::getLNRef).collect(Collectors.toList()); assertThat(resultSimpleDa).containsExactlyInAnyOrder( - // ...AndTrueInDai : If ValImport is True in DAI, DA is updatable - "LLN0.DoA.valImportNotSetAndTrueInDai", - "LLN0.DoA.valImportTrueAndTrueInDai", - "LLN0.DoA.valImportFalseAndTrueInDai", - // valImportTrue : If ValImport is True in DA and DAI does not exist, DA is updatable - "LLN0.DoA.valImportTrue", - // valImportTrueAndNotSetInDai : If ValImport is True in DA and DAI exists but DAI ValImport is not set, DA is updatable - "LLN0.DoA.valImportTrueAndNotSetInDai", - // Only these FC are updatable - "LLN0.DoA.fcCF", - "LLN0.DoA.fcDC", - "LLN0.DoA.fcSG", - "LLN0.DoA.fcSP", - "LLN0.DoA.fcST", - "LLN0.DoA.fcSE" + // ...AndTrueInDai : If ValImport is True in DAI, DA is updatable + "LLN0.DoA.valImportNotSetAndTrueInDai", + "LLN0.DoA.valImportTrueAndTrueInDai", + "LLN0.DoA.valImportFalseAndTrueInDai", + // valImportTrue : If ValImport is True in DA and DAI does not exist, DA is updatable + "LLN0.DoA.valImportTrue", + // valImportTrueAndNotSetInDai : If ValImport is True in DA and DAI exists but DAI ValImport is not set, DA is updatable + "LLN0.DoA.valImportTrueAndNotSetInDai", + // Only these FC are updatable + "LLN0.DoA.fcCF", + "LLN0.DoA.fcDC", + "LLN0.DoA.fcSG", + "LLN0.DoA.fcSP", + "LLN0.DoA.fcST", + "LLN0.DoA.fcSE" ); } @@ -445,34 +438,34 @@ void getDAI_should_filter_updatable_BDA() throws Exception { // then assertThat(dais).isNotNull(); List resultStructDa = dais.stream() - .filter(rdtt -> !rdtt.getBdaNames().isEmpty()) // test only struct DA - .map(ResumedDataTemplate::getLNRef).collect(Collectors.toList()); + .filter(rdtt -> !rdtt.getBdaNames().isEmpty()) // test only struct DA + .map(ResumedDataTemplate::getLNRef).collect(Collectors.toList()); assertThat(resultStructDa).containsExactlyInAnyOrder( - // ...AndTrueInDai : If ValImport is True in DAI, BDA is updatable - "LLN0.DoB.structValImportNotSet.bValImportFalseAndTrueInDai", - "LLN0.DoB.structValImportNotSet.bValImportNotSetAndTrueInDai", - "LLN0.DoB.structValImportNotSet.bValImportTrueAndTrueInDai", - "LLN0.DoB.structValImportTrue.bValImportFalseAndTrueInDai", - "LLN0.DoB.structValImportTrue.bValImportNotSetAndTrueInDai", - "LLN0.DoB.structValImportTrue.bValImportTrueAndTrueInDai", - "LLN0.DoB.structValImportFalse.bValImportFalseAndTrueInDai", - "LLN0.DoB.structValImportFalse.bValImportNotSetAndTrueInDai", - "LLN0.DoB.structValImportFalse.bValImportTrueAndTrueInDai", - // bValImportTrue : If ValImport is True in BDA and DAI does not exist, BDA is updatable - "LLN0.DoB.structValImportFalse.bValImportTrue", - "LLN0.DoB.structValImportTrue.bValImportTrue", - "LLN0.DoB.structValImportNotSet.bValImportTrue", - // bValImportTrueAndNotSetInDai : If ValImport is True in BDA and DAI exists but DAI ValImport is not set, BDA is updatable - "LLN0.DoB.structValImportTrue.bValImportTrueAndNotSetInDai", - "LLN0.DoB.structValImportNotSet.bValImportTrueAndNotSetInDai", - "LLN0.DoB.structValImportFalse.bValImportTrueAndNotSetInDai", - // Only these FC are updatable - "LLN0.DoB.structWithFcCF.bda1", - "LLN0.DoB.structWithFcDC.bda1", - "LLN0.DoB.structWithFcSG.bda1", - "LLN0.DoB.structWithFcSP.bda1", - "LLN0.DoB.structWithFcST.bda1", - "LLN0.DoB.structWithFcSE.bda1" + // ...AndTrueInDai : If ValImport is True in DAI, BDA is updatable + "LLN0.DoB.structValImportNotSet.bValImportFalseAndTrueInDai", + "LLN0.DoB.structValImportNotSet.bValImportNotSetAndTrueInDai", + "LLN0.DoB.structValImportNotSet.bValImportTrueAndTrueInDai", + "LLN0.DoB.structValImportTrue.bValImportFalseAndTrueInDai", + "LLN0.DoB.structValImportTrue.bValImportNotSetAndTrueInDai", + "LLN0.DoB.structValImportTrue.bValImportTrueAndTrueInDai", + "LLN0.DoB.structValImportFalse.bValImportFalseAndTrueInDai", + "LLN0.DoB.structValImportFalse.bValImportNotSetAndTrueInDai", + "LLN0.DoB.structValImportFalse.bValImportTrueAndTrueInDai", + // bValImportTrue : If ValImport is True in BDA and DAI does not exist, BDA is updatable + "LLN0.DoB.structValImportFalse.bValImportTrue", + "LLN0.DoB.structValImportTrue.bValImportTrue", + "LLN0.DoB.structValImportNotSet.bValImportTrue", + // bValImportTrueAndNotSetInDai : If ValImport is True in BDA and DAI exists but DAI ValImport is not set, BDA is updatable + "LLN0.DoB.structValImportTrue.bValImportTrueAndNotSetInDai", + "LLN0.DoB.structValImportNotSet.bValImportTrueAndNotSetInDai", + "LLN0.DoB.structValImportFalse.bValImportTrueAndNotSetInDai", + // Only these FC are updatable + "LLN0.DoB.structWithFcCF.bda1", + "LLN0.DoB.structWithFcDC.bda1", + "LLN0.DoB.structWithFcSG.bda1", + "LLN0.DoB.structWithFcSP.bda1", + "LLN0.DoB.structWithFcST.bda1", + "LLN0.DoB.structWithFcSE.bda1" ); } @@ -487,12 +480,12 @@ void getDAI_should_filter_updatable_DA_with_sGroup_Val() throws Exception { // then assertThat(dais).isNotNull(); List resultSimpleDa = dais.stream() - .filter(rdtt -> rdtt.getBdaNames().isEmpty()) // test only simple DA - .map(ResumedDataTemplate::getLNRef).collect(Collectors.toList()); + .filter(rdtt -> rdtt.getBdaNames().isEmpty()) // test only simple DA + .map(ResumedDataTemplate::getLNRef).collect(Collectors.toList()); assertThat(resultSimpleDa).containsExactlyInAnyOrder( - "LLN0.DoD.sGroupValImportNotSet", - "LLN0.DoD.sGroupValImportTrue" - ); + "LLN0.DoD.sGroupValImportNotSet", + "LLN0.DoD.sGroupValImportTrue" + ); } @Test @@ -505,23 +498,25 @@ void getDAI_should_filter_updatable_DA_with_sGroup_Val_without_ConfSg() throws E // then assertThat(dais) - .isNotNull() - .isEmpty(); + .isNotNull() + .isEmpty(); } @Test void testInitScl() { - assertDoesNotThrow( + SclRootAdapter sclRootAdapter = assertDoesNotThrow( () -> SclService.initScl(Optional.empty(), "hVersion", "hRevision") ); + assertIsMarshallable(sclRootAdapter.getCurrentElem()); } @Test void testInitScl_With_hId_shouldNotThrowError() { UUID hid = UUID.randomUUID(); - assertDoesNotThrow( + SclRootAdapter sclRootAdapter = assertDoesNotThrow( () -> SclService.initScl(Optional.of(hid), "hVersion", "hRevision") ); + assertIsMarshallable(sclRootAdapter.getCurrentElem()); } @Test @@ -531,7 +526,8 @@ void testInitScl_Create_Private_SCL_FILETYPE() { () -> SclService.initScl(Optional.of(hid), "hVersion", "hRevision") ); assertThat(rootAdapter.getCurrentElem().getPrivate()).isNotEmpty(); - assertThat(rootAdapter.getCurrentElem().getPrivate().get(0).getType()).isEqualTo(CommonConstants.COMPAS_SCL_FILE_TYPE); + assertThat(rootAdapter.getCurrentElem().getPrivate().get(0).getType()).isEqualTo(COMPAS_SCL_FILE_TYPE.getPrivateType()); + assertIsMarshallable(rootAdapter.getCurrentElem()); } @Test @@ -543,8 +539,7 @@ void testUpdateHeader() { UUID hId = UUID.fromString(sclRootAdapter.getHeaderAdapter().getHeaderId()); HeaderDTO headerDTO = DTO.createHeaderDTO(hId); SclService.updateHeader(sclRootAdapter.getCurrentElem(), headerDTO); - SclService.updateHeader(sclRootAdapter.getCurrentElem(), headerDTO); - + assertIsMarshallable(sclRootAdapter.getCurrentElem()); } @Test @@ -552,7 +547,6 @@ void testUpdateDAI() throws Exception { ResumedDataTemplate rDtt = new ResumedDataTemplate(); rDtt.setLnType("unknownID"); SCL scd = SclTestMarshaller.getSCLFromFile("/ied-test-schema-conf/ied_unit_test.xml"); - SclRootAdapter sclRootAdapter = new SclRootAdapter(scd); assertThrows(ScdException.class, () -> SclService.updateDAI( scd, "IED", "LD", rDtt @@ -566,7 +560,7 @@ void testUpdateDAI() throws Exception { tVal.setValue("newValue"); rDtt.setDaiValues(List.of(tVal)); assertDoesNotThrow(() -> SclService.updateDAI(scd, "IED_NAME", "LD_INS1", rDtt)); - + assertIsMarshallable(scd); } @Test @@ -580,52 +574,6 @@ void testGetEnumTypeElements() throws Exception { assertFalse(enumList.isEmpty()); } - @ParameterizedTest - @ValueSource(strings = {"/scd-substation-import-ssd/ssd_with_2_substations.xml", "/scd-substation-import-ssd/ssd_without_substations.xml"}) - void testAddSubstation_Check_SSD_Validity(String ssdFileName) throws Exception { - SCL scd = SclTestMarshaller.getSCLFromFile("/scl-root-test-schema-conf/add_ied_test.xml"); - SCL ssd = SclTestMarshaller.getSCLFromFile(ssdFileName); - - assertThrows(ScdException.class, - () -> SclService.addSubstation(scd, ssd)); - } - - @Test - void testAddSubstation_SCD_Without_Substation() throws Exception { - SCL scd = SclTestMarshaller.getSCLFromFile("/scl-root-test-schema-conf/add_ied_test.xml"); - SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); - SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); - SclRootAdapter ssdRootAdapter = new SclRootAdapter(ssd); - SclRootAdapter expectedScdAdapter = SclService.addSubstation(scd, ssd); - - assertNotEquals(scdRootAdapter, expectedScdAdapter); - assertEquals(expectedScdAdapter.getCurrentElem().getSubstation(), ssdRootAdapter.getCurrentElem().getSubstation()); - } - - @Test - void testAddSubstation_SCD_With_Different_Substation_Name() throws Exception { - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/scd_with_substation_name_different.xml"); - SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); - - assertThrows(ScdException.class, - () -> SclService.addSubstation(scd, ssd)); - } - - @Test - void testAddSubstation_SCD_With_Substation() throws Exception { - SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/scd_with_substation.xml"); - SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); - SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); - SclRootAdapter ssdRootAdapter = new SclRootAdapter(ssd); - SclRootAdapter expectedScdAdapter = SclService.addSubstation(scd, ssd); - TSubstation expectedTSubstation = expectedScdAdapter.getCurrentElem().getSubstation().get(0); - TSubstation tSubstation = ssdRootAdapter.getCurrentElem().getSubstation().get(0); - - assertNotEquals(scdRootAdapter, expectedScdAdapter); - assertEquals(expectedTSubstation.getName(), tSubstation.getName()); - assertEquals(expectedTSubstation.getVoltageLevel().size(), tSubstation.getVoltageLevel().size()); - } - @Test void testImportSTDElementsInSCD() throws Exception { SCL scd = SclTestMarshaller.getSCLFromFile("/scd-ied-dtt-com-import-stds/scd.xml"); @@ -637,6 +585,7 @@ void testImportSTDElementsInSCD() throws Exception { assertThat(expectedScdAdapter.getCurrentElem().getIED()).hasSize(1); assertThat(expectedScdAdapter.getCurrentElem().getDataTypeTemplates()).hasNoNullFieldsOrProperties(); assertThat(expectedScdAdapter.getCurrentElem().getCommunication().getSubNetwork()).hasSize(2); + assertIsMarshallable(scd); } @Test @@ -654,6 +603,7 @@ void testImportSTDElementsInSCD_with_Multiple_STD() throws Exception { assertThat(expectedScdAdapter.getCurrentElem().getCommunication().getSubNetwork()).hasSize(2); assertThat(expectedScdAdapter.getCurrentElem().getCommunication().getSubNetwork().get(0).getConnectedAP()).hasSizeBetween(1,3); assertThat(expectedScdAdapter.getCurrentElem().getCommunication().getSubNetwork().get(1).getConnectedAP()).hasSizeBetween(1,3); + assertIsMarshallable(scd); } @Test @@ -664,7 +614,7 @@ void testImportSTDElementsInSCD_Several_STD_Match_Compas_ICDHeader() throws Exce SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); assertThrows(ScdException.class, () -> SclService.importSTDElementsInSCD(scdRootAdapter, Set.of(std, std1), DTO.comMap)); - + assertIsMarshallable(scd); } @Test @@ -674,7 +624,7 @@ void testImportSTDElementsInSCD_Compas_ICDHeader_Not_Match() throws Exception { SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); assertThrows(ScdException.class, ()-> SclService.importSTDElementsInSCD(scdRootAdapter, Set.of(std), DTO.comMap)); - + assertIsMarshallable(scd); } @Test @@ -683,6 +633,72 @@ void testImportSTDElementsInSCD_No_STD_Match() throws Exception { SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); assertThrows(ScdException.class, ()-> SclService.importSTDElementsInSCD(scdRootAdapter, new HashSet<>(), DTO.comMap)); - + assertIsMarshallable(scd); + } + + @Test + void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_controlBlocks_and_Dataset_on_ln0() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml"); + // When + SclService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl); + // Then + SclRootAdapter scdRootAdapter = new SclRootAdapter(scl); + List lDevices = scdRootAdapter.getIEDAdapters().stream().map(IEDAdapter::getLDeviceAdapters) + .flatMap(List::stream).collect(Collectors.toList()); + List ln0s = lDevices.stream().map(LDeviceAdapter::getLN0Adapter).map(LN0Adapter::getCurrentElem).collect(Collectors.toList()); + assertThat(ln0s) + .isNotEmpty() + .noneMatch(TAnyLN::isSetDataSet) + .noneMatch(TAnyLN::isSetLogControl) + .noneMatch(TAnyLN::isSetReportControl) + .noneMatch(LN0::isSetGSEControl) + .noneMatch(LN0::isSetSampledValueControl); + assertIsMarshallable(scl); + } + + @Test + void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_controlBlocks_and_Dataset_on_ln() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml"); + // When + SclService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl); + // Then + SclRootAdapter scdRootAdapter = new SclRootAdapter(scl); + List lDevices = scdRootAdapter.getIEDAdapters().stream().map(IEDAdapter::getLDeviceAdapters) + .flatMap(List::stream).collect(Collectors.toList()); + List lns = lDevices.stream().map(LDeviceAdapter::getLNAdapters).flatMap(List::stream) + .map(LNAdapter::getCurrentElem).collect(Collectors.toList()); + assertThat(lns) + .isNotEmpty() + .noneMatch(TAnyLN::isSetDataSet) + .noneMatch(TAnyLN::isSetLogControl) + .noneMatch(TAnyLN::isSetReportControl); + assertIsMarshallable(scl); + } + + @Test + void removeControlBlocksAndDatasetAndExtRefSrc_should_remove_srcXXX_attributes_on_ExtRef() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml"); + // When + SclService.removeAllControlBlocksAndDatasetsAndExtRefSrcBindings(scl); + // Then + SclRootAdapter scdRootAdapter = new SclRootAdapter(scl); + List extRefs = scdRootAdapter + .getIEDAdapters().stream() + .map(IEDAdapter::getLDeviceAdapters).flatMap(List::stream) + .map(LDeviceAdapter::getLN0Adapter) + .map(AbstractLNAdapter::getExtRefs).flatMap(List::stream) + .collect(Collectors.toList()); + assertThat(extRefs) + .isNotEmpty() + .noneMatch(TExtRef::isSetSrcLDInst) + .noneMatch(TExtRef::isSetSrcPrefix) + .noneMatch(TExtRef::isSetSrcLNInst) + .noneMatch(TExtRef::isSetSrcCBName) + .noneMatch(TExtRef::isSetSrcLNClass); + assertIsMarshallable(scl); } + } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SubstationServiceTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SubstationServiceTest.java new file mode 100644 index 000000000..4f2a23a9e --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/SubstationServiceTest.java @@ -0,0 +1,195 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.SCL; +import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader; +import org.lfenergy.compas.scl2007b4.model.TLNode; +import org.lfenergy.compas.scl2007b4.model.TSubstation; +import org.lfenergy.compas.sct.commons.exception.ScdException; +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.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; + +class SubstationServiceTest { + + public static final String XPATH_FUNCTION_BAY_1_TDCL = "/SCL/Substation[@name=\"SITE\"]/VoltageLevel[@name=\"voltageLevelName\"]/Bay[@name=\"bay1\"]/Function[@name=\"bay1TDCL\"]"; + + public static final String XPATH_LNODE_RADR = XPATH_FUNCTION_BAY_1_TDCL + "/LNode[@iedName=\"None\" and not(@ldInst) and not(@Prefix) and @lnClass=\"RADR\" and not(@lnInst)]"; + + @Test + void addSubstation_when_SCD_has_no_substation_should_succeed() throws Exception { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scl-root-test-schema-conf/add_ied_test.xml"); + SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); + SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); + SclRootAdapter ssdRootAdapter = new SclRootAdapter(ssd); + // When + SclRootAdapter resultScdAdapter = SubstationService.addSubstation(scd, ssd); + // Then + assertNotEquals(scdRootAdapter, resultScdAdapter); + assertEquals(resultScdAdapter.getCurrentElem().getSubstation(), ssdRootAdapter.getCurrentElem().getSubstation()); + assertIsMarshallable(scd); + } + + @Test + void addSubstation_when_SCD_has_a_substation_should_succeed() throws Exception { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/scd_with_substation.xml"); + SclRootAdapter scdRootAdapter = new SclRootAdapter(scd); + SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); + SclRootAdapter ssdRootAdapter = new SclRootAdapter(ssd); + TSubstation ssdSubstation = ssdRootAdapter.getCurrentElem().getSubstation().get(0); + // When + SclRootAdapter resultScdAdapter = SubstationService.addSubstation(scd, ssd); + // Then + TSubstation resultSubstation = resultScdAdapter.getCurrentElem().getSubstation().get(0); + assertNotEquals(scdRootAdapter, resultScdAdapter); + assertEquals(ssdSubstation.getName(), resultSubstation.getName()); + assertEquals(ssdSubstation.getVoltageLevel().size(), resultSubstation.getVoltageLevel().size()); + assertIsMarshallable(scd); + } + + @Test + void addSubstation_when_SSD_with_multiple_Substations_should_throw_exception() throws Exception { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scl-root-test-schema-conf/add_ied_test.xml"); + SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd_with_2_substations.xml"); + + // When & Then + assertThrows(ScdException.class, () -> SubstationService.addSubstation(scd, ssd)); + } + + @Test + void addSubstation_when_SSD_with_no_substation_should_throw_exception() throws Exception { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scl-root-test-schema-conf/add_ied_test.xml"); + SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd_without_substations.xml"); + + // When & Then + assertThrows(ScdException.class, () -> SubstationService.addSubstation(scd, ssd)); + } + + @Test + void addSubstation_when_substations_names_differ_should_throw_exception() throws Exception { + // Given + SCL scd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/scd_with_substation_name_different.xml"); + SCL ssd = SclTestMarshaller.getSCLFromFile("/scd-substation-import-ssd/ssd.xml"); + // When & Then + assertThrows(ScdException.class, () -> SubstationService.addSubstation(scd, ssd)); + } + + @Test + void updateLNodeIEDNames_when_LNode_has_single_private_should_set_IedName() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + // When + SubstationService.updateLNodeIEDNames(scl); + // Then + assertThat(scl.getSubstation()).hasSize(1); + assertThat(scl.getSubstation().get(0).getVoltageLevel()).hasSize(1); + assertThat(scl.getSubstation().get(0).getVoltageLevel().get(0).getBay()).hasSize(1); + assertThat(scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction()).hasSize(1); + List lNodes = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode(); + assertThat(lNodes).extracting(TLNode::getIedName).containsOnlyOnce("iedName1"); + assertIsMarshallable(scl); + } + + @Test + void updateLNodeIEDNames_when_LNode_has_multiples_private_should_set_IedName() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + // When + SubstationService.updateLNodeIEDNames(scl); + // Then + assertThat(scl.getSubstation()).hasSize(1); + assertThat(scl.getSubstation().get(0).getVoltageLevel()).hasSize(1); + assertThat(scl.getSubstation().get(0).getVoltageLevel().get(0).getBay()).hasSize(1); + assertThat(scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction()).hasSize(1); + List lNodes = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode(); + assertThat(lNodes) + .hasSize(4) + .extracting(TLNode::getIedName) + .containsExactly("iedName1", "iedName2", "iedName3", "iedName4"); + assertThat(lNodes.subList(1, 4)).allSatisfy( + tlNode -> assertThat(tlNode) + .hasFieldOrPropertyWithValue("lnClass", List.of("LPHD")) + .hasFieldOrPropertyWithValue("ldInst", "ldInst1") + .hasFieldOrPropertyWithValue("lnInst", "1") + .hasFieldOrPropertyWithValue("lnType", "lnType1")); + assertThat(lNodes.subList(1, 4)).allSatisfy(tlNode -> + assertThat(tlNode.getPrivate()) + .isNotEmpty() + .allSatisfy(tPrivate -> assertThat(PrivateService.getCompasICDHeader(tPrivate)).isPresent())); + assertIsMarshallable(scl); + } + + @Test + void updateLNodeIEDNames_when_private_is_missing_should_throw_exception() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + List lNodes = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode(); + lNodes.get(0).unsetPrivate(); + // When & Then + assertThatThrownBy(() -> SubstationService.updateLNodeIEDNames(scl)).isInstanceOf(ScdException.class) + .hasMessage(XPATH_FUNCTION_BAY_1_TDCL + " doesn't contain any Private/compas:ICDHeader"); + } + + @Test + void updateLNodeIEDNames_when_private_is_empty_should_throw_exception() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + List lNodes = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode(); + lNodes.get(0).getPrivate().clear(); + // When & Then + assertThatThrownBy(() -> SubstationService.updateLNodeIEDNames(scl)).isInstanceOf(ScdException.class) + .hasMessage(XPATH_FUNCTION_BAY_1_TDCL + " doesn't contain any" + + " Private/compas:ICDHeader");; + } + + @Test + void updateLNodeIEDNames_when_private_iedName_is_empty_should_throw_exception() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + TLNode lNode = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode().get(0); + PrivateService.getCompasPrivates(lNode, TCompasICDHeader.class).get(0).setIEDName(""); + // When & Then + assertThatThrownBy(() -> SubstationService.updateLNodeIEDNames(scl)).isInstanceOf(ScdException.class) + .hasMessage(XPATH_LNODE_RADR + "/Private/compas:ICDHeader/@IEDName is missing or is blank");; + } + + @Test + void updateLNodeIEDNames_when_private_iedName_is_missing_should_throw_exception() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + TLNode lNode = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode().get(0); + List compasPrivates = PrivateService.getCompasPrivates(lNode, TCompasICDHeader.class); + assertThat(compasPrivates).hasSize(1); + compasPrivates.get(0).setIEDName(null); + // When & Then + assertThatThrownBy(() -> SubstationService.updateLNodeIEDNames(scl)).isInstanceOf(ScdException.class) + .hasMessage(XPATH_LNODE_RADR + "/Private/compas:ICDHeader/@IEDName is missing or is blank");; + } + + @Test + void updateLNodeIEDNames_when_private_iedName_is_missing_and_has_multiple_privates_should_throw_exception() throws Exception { + // Given + SCL scl = SclTestMarshaller.getSCLFromFile("/scd-refresh-lnode/scd-with-substation-lnode.xml"); + TLNode lNode = scl.getSubstation().get(0).getVoltageLevel().get(0).getBay().get(0).getFunction().get(0).getLNode().get(1); + List compasPrivates = PrivateService.getCompasPrivates(lNode, TCompasICDHeader.class); + assertThat(compasPrivates).hasSize(3); + compasPrivates.get(0).setIEDName(null); + // When & Then + assertThatThrownBy(() -> SubstationService.updateLNodeIEDNames(scl)).isInstanceOf(ScdException.class) + .hasMessage(XPATH_FUNCTION_BAY_1_TDCL + "/LNode[@iedName=\"None\" and @ldInst=\"ldInst1\" and @Prefix=\"prefix1\" and @lnClass=\"LPHD\" and @lnInst=\"1\"]/Private/compas:ICDHeader/@IEDName is missing or is blank");; + } + +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapterTest.java index f31403f39..5fca85bf4 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/dtt/DataTypeTemplateAdapterTest.java @@ -367,6 +367,6 @@ void addPrivate() throws Exception { TPrivate tPrivate = new TPrivate(); tPrivate.setType("Private Type"); tPrivate.setSource("Private Source"); - assertThrows(IllegalArgumentException.class, () -> dttAdapter.addPrivate(tPrivate)); + assertThrows(UnsupportedOperationException.class, () -> dttAdapter.addPrivate(tPrivate)); } -} \ No newline at end of file +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapterTest.java index 8901c4487..7c7597891 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/header/HeaderAdapterTest.java @@ -66,7 +66,7 @@ void addPrivate() throws Exception { TPrivate tPrivate = new TPrivate(); tPrivate.setType("Private Type"); tPrivate.setSource("Private Source"); - assertThrows(IllegalArgumentException.class, () -> hAdapter.addPrivate(tPrivate)); + assertThrows(UnsupportedOperationException.class, () -> hAdapter.addPrivate(tPrivate)); } -} \ No newline at end of file +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java index 4fbad1dba..d848c7199 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/DOIAdapterTest.java @@ -77,7 +77,7 @@ void testInnerDAIAdapterTestUpdateWithMapAsArg(){ assertDoesNotThrow(() -> daiAdapter.update(vals)); assertFalse(daiAdapter.getCurrentElem().getVal().isEmpty()); TVal tVal = daiAdapter.getCurrentElem().getVal().get(0); - assertNull(tVal.getSGroup()); + assertFalse(tVal.isSetSGroup()); final Map vals2 = new HashMap<>(); vals2.put(1L,TOTO); @@ -85,7 +85,7 @@ void testInnerDAIAdapterTestUpdateWithMapAsArg(){ assertDoesNotThrow(() -> daiAdapter.update(vals2)); assertFalse(daiAdapter.getCurrentElem().getVal().isEmpty()); tVal = daiAdapter.getCurrentElem().getVal().get(0); - assertNull(tVal.getSGroup()); + assertFalse(tVal.isSetSGroup()); } @Test @@ -156,4 +156,4 @@ void addPrivate() { daiAdapter.addPrivate(tPrivate); assertEquals(1, daiAdapter.getCurrentElem().getPrivate().size()); } -} \ No newline at end of file +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java index 320ad9886..b75e19ff6 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/IEDAdapterTest.java @@ -13,7 +13,6 @@ import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.ObjectReference; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; -import org.lfenergy.compas.sct.commons.testhelpers.MarshallerWrapper; import org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller; import org.mockito.Mockito; @@ -22,6 +21,7 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.sct.commons.testhelpers.SclTestMarshaller.assertIsMarshallable; class IEDAdapterTest { @@ -155,8 +155,7 @@ void testCreateDataSet() throws Exception { dataSetInfo.setHolderLnClass(TLLN0Enum.LLN_0.value()); assertDoesNotThrow(() -> iAdapter.createDataSet(dataSetInfo)); - MarshallerWrapper marshallerWrapper = SclTestMarshaller.createWrapper(); - System.out.println(marshallerWrapper.marshall(scd)); + assertIsMarshallable(scd); } @Test @@ -227,6 +226,7 @@ void createControlBlock() throws Exception { controlBlock.setHolderIEDName("IED_NAME"); controlBlock.setHolderIEDName("IED_NAME"); controlBlock.setHolderIEDName("IED_NAME"); + assertIsMarshallable(scd); } @Test @@ -244,4 +244,4 @@ void addPrivate() { iAdapter.addPrivate(tPrivate); assertEquals(1, iAdapter.getCurrentElem().getPrivate().size()); } -} \ No newline at end of file +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapterTest.java index 9acc23cc2..e36aab2c9 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapterTest.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/BayAdapterTest.java @@ -6,13 +6,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.lfenergy.compas.scl2007b4.model.TBay; -import org.lfenergy.compas.scl2007b4.model.TPrivate; -import org.lfenergy.compas.scl2007b4.model.TSubstation; -import org.lfenergy.compas.scl2007b4.model.TVoltageLevel; +import org.lfenergy.compas.scl2007b4.model.*; import org.lfenergy.compas.sct.commons.exception.ScdException; import org.lfenergy.compas.sct.commons.scl.SclRootAdapter; +import java.util.stream.Stream; + import static org.junit.jupiter.api.Assertions.*; class BayAdapterTest { @@ -34,6 +33,7 @@ public void init() throws ScdException { vLevelAdapter = ssAdapter.getVoltageLevelAdapter("VOLTAGE_LEVEL").get(); TBay tBay = new TBay(); tBay.setName("BAY"); + tBay.getFunction().add(new TFunction()); vLevelAdapter.getCurrentElem().getBay().add(tBay); bayAdapter = vLevelAdapter.getBayAdapter("BAY").get(); @@ -74,4 +74,32 @@ void addPrivate() { bayAdapter.addPrivate(tPrivate); assertEquals(1, bayAdapter.getCurrentElem().getPrivate().size()); } -} \ No newline at end of file + + @Test + void elementXPath_should_succeed() { + // Given : init + // When + String result = bayAdapter.elementXPath(); + // Then + assertEquals("Bay[@name=\"BAY\"]", result); + } + + @Test + void elementXPath_when_name_is_missing_should_succeed() { + // Given : init + bayAdapter.getCurrentElem().setName(null); + // When + String result = bayAdapter.elementXPath(); + // Then + assertEquals("Bay[not(@name)]", result); + } + + @Test + void streamFunctionAdapters() { + // Given : init + // When + Stream result = bayAdapter.streamFunctionAdapters(); + // Then + assertEquals(1, result.count()); + } +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/FunctionAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/FunctionAdapterTest.java new file mode 100644 index 000000000..c213fffa3 --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/FunctionAdapterTest.java @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl.sstation; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.TBay; +import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader; +import org.lfenergy.compas.scl2007b4.model.TFunction; +import org.lfenergy.compas.scl2007b4.model.TLNode; +import org.lfenergy.compas.sct.commons.exception.ScdException; +import org.lfenergy.compas.sct.commons.scl.PrivateService; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class FunctionAdapterTest { + + private FunctionAdapter functionAdapter; + + @BeforeEach + void setUp() { + TBay tBay = new TBay(); + BayAdapter bayAdapter = new BayAdapter(null, tBay); + TFunction tFunction = new TFunction(); + tFunction.setName("functionName"); + tBay.getFunction().add(tFunction); + functionAdapter = new FunctionAdapter(bayAdapter, tFunction); + } + + @Test + void amChildElementRef_should_succeed() { + // Given : setUp + // When + boolean result = functionAdapter.amChildElementRef(); + // Then + assertThat(result).isTrue(); + } + + @Test + void amChildElementRef_when_parent_does_not_contain_function_should_be_false() { + // Given : setUp + functionAdapter.getParentAdapter().getCurrentElem().getFunction().clear(); + // When + boolean result = functionAdapter.amChildElementRef(); + // Then + assertThat(result).isFalse(); + } + + @Test + void elementXPath() { + // Given : setUp + // When + String result = functionAdapter.elementXPath(); + // Then + assertThat(result).isEqualTo("Function[@name=\"functionName\"]"); + } + + @Test + void updateLNodeIedNames_when_one_private_should_succeed() { + // Given + TLNode tlNode = new TLNode(); + TCompasICDHeader tCompasICDHeader = new TCompasICDHeader(); + tCompasICDHeader.setIEDName("iedName1"); + tlNode.getPrivate().add(PrivateService.createPrivate(tCompasICDHeader)); + functionAdapter.getCurrentElem().getLNode().add(tlNode); + // When + functionAdapter.updateLNodeIedNames(); + // Then + assertThat(functionAdapter.getCurrentElem().getLNode()) + .hasSize(1) + .map(TLNode::getIedName).containsExactly("iedName1"); + } + + @Test + void updateLNodeIedNames_when_multiples_privates_should_succeed() { + // Given + TLNode tlNode = new TLNode(); + TCompasICDHeader tCompasICDHeader1 = new TCompasICDHeader(); + tCompasICDHeader1.setIEDName("iedName1"); + TCompasICDHeader tCompasICDHeader2 = new TCompasICDHeader(); + tCompasICDHeader2.setIEDName("iedName2"); + TCompasICDHeader tCompasICDHeader3 = new TCompasICDHeader(); + tCompasICDHeader3.setIEDName("iedName3"); + tlNode.getPrivate().add(PrivateService.createPrivate(tCompasICDHeader1)); + tlNode.getPrivate().add(PrivateService.createPrivate(tCompasICDHeader2)); + tlNode.getPrivate().add(PrivateService.createPrivate(tCompasICDHeader3)); + functionAdapter.getCurrentElem().getLNode().add(tlNode); + // When + functionAdapter.updateLNodeIedNames(); + // Then + assertThat(functionAdapter.getCurrentElem().getLNode()) + .hasSize(3) + .map(TLNode::getIedName) + .containsExactly("iedName1", "iedName2", "iedName3"); + } + + @Test + void updateLNodeIedNames_when_no_private_should_throw_exception() { + // Given + TLNode tlNode = new TLNode(); + functionAdapter.getCurrentElem().getLNode().add(tlNode); + // When & Then + assertThatThrownBy(() -> functionAdapter.updateLNodeIedNames()).isInstanceOf(ScdException.class); + } + +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/LNodeAdapterTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/LNodeAdapterTest.java new file mode 100644 index 000000000..7429cfdca --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/sstation/LNodeAdapterTest.java @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.scl.sstation; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.lfenergy.compas.scl2007b4.model.*; +import org.lfenergy.compas.sct.commons.scl.PrivateService; + +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class LNodeAdapterTest { + + @Test + void constructor_should_create_LNode_with_no_parents() { + // Given + TLNode tlNode = new TLNode(); + // When + LNodeAdapter lNodeAdapter = new LNodeAdapter(null, tlNode); + // Then + assertThat(lNodeAdapter.getParentAdapter()).isNull(); + } + + @Test + void constructor_when_LNode_is_child_of_parent_should_succeed() { + // Given + TLNode tlNode = new TLNode(); + TFunction tFunction = new TFunction(); + tFunction.getLNode().add(tlNode); + FunctionAdapter functionAdapter = new FunctionAdapter(null, tFunction); + // When + LNodeAdapter lNodeAdapter = new LNodeAdapter(functionAdapter, tlNode); + // Then + assertThat(lNodeAdapter.getParentAdapter()).isNotNull(); + } + + @Test + void constructor_when_LNode_is_not_child_of_parent_should_throw_exception() { + // Given + TLNode tlNode = new TLNode(); + TFunction tFunction = new TFunction(); + FunctionAdapter functionAdapter = new FunctionAdapter(null, tFunction); + // When & Then + assertThatThrownBy(() -> new LNodeAdapter(functionAdapter, tlNode)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void addPrivate_should_succeed() { + // Given + TLNode tlNode = new TLNode(); + LNodeAdapter lNodeAdapter = new LNodeAdapter(null, tlNode); + TPrivate tPrivate = PrivateService.createPrivate(TCompasSclFileType.SCD); + // When + lNodeAdapter.addPrivate(tPrivate); + // Then + assertThat(tlNode.getPrivate()).hasSize(1); + assertThat(tlNode.getPrivate().get(0).getContent()).hasSize(1).first().isInstanceOf(JAXBElement.class); + JAXBElement jaxbElement = (JAXBElement) tlNode.getPrivate().get(0).getContent().get(0); + assertThat(jaxbElement.getValue()).isEqualTo(TCompasSclFileType.SCD); + } + + @Test + void deepCopy_should_succeed() { + // Given + TLNode tlNode = new TLNode(); + tlNode.setIedName("iedName1"); + tlNode.setLdInst("ldInst1"); + tlNode.setPrefix("prefix1"); + tlNode.getLnClass().add("lnClass1"); + tlNode.setLnInst("lnInst1"); + tlNode.setLnType("lnType1"); + tlNode.setDesc("Desc1"); + tlNode.getAny().add("any1"); + TText tText = new ObjectFactory().createTText(); + tText.setSource("Text1"); + tText.getContent().add("Text1"); + tText.getOtherAttributes().put(QName.valueOf("Text1_attribute1"), "Text1_value1"); + tlNode.setText(tText); + tlNode.getPrivate().add(PrivateService.createPrivate(TCompasSclFileType.SCD)); + tlNode.getOtherAttributes().put(QName.valueOf("tlNode_attribute1"), "tlNode_value1"); + LNodeAdapter lNodeAdapter = new LNodeAdapter(null, tlNode); + // When + TLNode result = lNodeAdapter.deepCopy(); + // Then + assertThat(result).usingRecursiveComparison().isEqualTo(tlNode); + List fields = ReflectionSupport.findFields(TLNode.class, field -> true, HierarchyTraversalMode.BOTTOM_UP); + assertThat(fields).isNotEmpty().allSatisfy( + field -> { + Optional optionalValue = ReflectionSupport.tryToReadFieldValue(field, result).toOptional(); + assertThat(optionalValue).isPresent(); + Object value = optionalValue.get(); + if (value instanceof Collection) { + assertThat((Collection) value).isNotEmpty(); + } else { + assertThat(value).isNotNull(); + } + } + ); + } +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/MarshallerWrapper.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/MarshallerWrapper.java index 92fb85aa0..3e61a8b87 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/MarshallerWrapper.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/MarshallerWrapper.java @@ -41,7 +41,7 @@ public String marshall(final T obj) { return sw.toString(); } catch (JAXBException exp) { String message = String.format("Error marshalling the Class: %s", exp); - log.error(message); + log.error(message, exp); throw new CompasException(CompasErrorCode.MARSHAL_ERROR_CODE, message); } } diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclTestMarshaller.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclTestMarshaller.java index c0fc4850d..ac80d9ddb 100644 --- a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclTestMarshaller.java +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/testhelpers/SclTestMarshaller.java @@ -7,6 +7,8 @@ import org.apache.commons.io.IOUtils; import org.lfenergy.compas.scl2007b4.model.SCL; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + public class SclTestMarshaller { public static SCL getSCLFromFile(String filename) throws Exception { @@ -15,7 +17,12 @@ public static SCL getSCLFromFile(String filename) throws Exception { return marshallerWrapper.unmarshall(rawXml,SCL.class); } - public static MarshallerWrapper createWrapper() { + public static String assertIsMarshallable(SCL scl) { + MarshallerWrapper marshallerWrapper = createWrapper(); + return assertDoesNotThrow(() -> marshallerWrapper.marshall(scl)); + } + + private static MarshallerWrapper createWrapper() { return MarshallerWrapper.builder() .withProperties("classpath:scl_schema.yml") .build(); diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/CommonConstantsTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/CommonConstantsTest.java new file mode 100644 index 000000000..d4930c0df --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/CommonConstantsTest.java @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.support.ReflectionSupport; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CommonConstantsTest { + + @Test + void constructor_should_throw_exception() { + // Given + // When & Then + assertThatThrownBy(() -> ReflectionSupport.newInstance(Utils.class)) + .isInstanceOf(UnsupportedOperationException.class); + } + +} diff --git a/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/PrivateEnumTest.java b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/PrivateEnumTest.java new file mode 100644 index 000000000..0a0b59a3e --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/PrivateEnumTest.java @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2022 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl2007b4.model.TCompasSclFileType; + +import java.util.NoSuchElementException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class PrivateEnumTest { + + @Test + void fromClass_should_return_PrivateEnum() { + // Given + Class compasClass = TCompasSclFileType.class; + // When + PrivateEnum result = PrivateEnum.fromClass(compasClass); + // Then + assertThat(result).isEqualTo(PrivateEnum.COMPAS_SCL_FILE_TYPE); + } + + @Test + void fromClass_with_unknown_class_should_throw_exception() { + // Given + Class classToTest = Object.class; + // When & Then + assertThatThrownBy(() -> PrivateEnum.fromClass(classToTest)).isInstanceOf(NoSuchElementException.class); + } + + @Test + void toString_should_return_private_type() { + // Given + PrivateEnum privateEnum = PrivateEnum.COMPAS_SCL_FILE_TYPE; + // When + String result = privateEnum.toString(); + // Then + assertThat(result).isEqualTo("COMPAS-SclFileType"); + } + +} 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 new file mode 100644 index 000000000..24ea812f3 --- /dev/null +++ b/sct-commons/src/test/java/org/lfenergy/compas/sct/commons/util/UtilsTest.java @@ -0,0 +1,190 @@ +// SPDX-FileCopyrightText: 2021 RTE FRANCE +// +// SPDX-License-Identifier: Apache-2.0 + +package org.lfenergy.compas.sct.commons.util; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.platform.commons.support.ReflectionSupport; + +import java.util.*; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + + +class UtilsTest { + + @Test + void constructor_should_throw_exception() { + // Given + // When & Then + assertThatThrownBy(() -> ReflectionSupport.newInstance(Utils.class)) + .isInstanceOf(UnsupportedOperationException.class); + } + + @Test + void entering_should_return_text() { + // Given : method name + // When + String entering = Utils.entering(); + // Then + assertEquals(">>> Entering: ::entering_should_return_text", entering); + } + + @Test + void leaving_should_return_text() { + // Given : method name + // When + String leaving = Utils.leaving(); + // Then + assertEquals("<<< Leaving: ::leaving_should_return_text", leaving); + } + + @Test + void leaving_should_return_text_with_time() { + // Given : method name + // When + String leaving = Utils.leaving(System.nanoTime()); + // Then + assertTrue(leaving.matches("<<< Leaving: ::leaving_should_return_text_with_time - Timer duration: .* sec."), leaving); + } + + @Test + void leaving_should_return_text_with_invalid_time() { + // Given : method name + // When + String leaving = Utils.leaving(-1L); + // Then + assertEquals("<<< Leaving: ::leaving_should_return_text_with_invalid_time", leaving); + } + + @Test + void equalsOrNotSet_should_return_true_when_both_values_are_not_set() { + // Given + Optional object1 = Optional.empty(); + Optional object2 = Optional.empty(); + // When + boolean result1 = Utils.equalsOrNotSet(object1, object2, Optional::isPresent, Optional::get); + boolean result2 = Utils.equalsOrNotSet(object2, object1, Optional::isPresent, Optional::get); + // Then + assertTrue(result1); + assertTrue(result2); + } + + @Test + void equalsOrNotSet_should_return_true_when_both_values_are_set_and_equal() { + // Given + Optional object1 = Optional.of(1L); + Optional object2 = Optional.of(1L); + // When + boolean result1 = Utils.equalsOrNotSet(object1, object2, Optional::isPresent, Optional::get); + boolean result2 = Utils.equalsOrNotSet(object2, object1, Optional::isPresent, Optional::get); + // Then + assertTrue(result1); + assertTrue(result2); + } + + @Test + void equalsOrNotSet_should_return_false_when_both_values_are_set_but_differ() { + // Given + Optional object1 = Optional.of(1L); + Optional object2 = Optional.of(2L); + // When + boolean result1 = Utils.equalsOrNotSet(object1, object2, Optional::isPresent, Optional::get); + boolean result2 = Utils.equalsOrNotSet(object2, object1, Optional::isPresent, Optional::get); + // Then + assertFalse(result1); + assertFalse(result2); + } + + @Test + void equalsOrNotSet_should_return_false_when_one_is_set_and_the_other_is_not() { + // Given + Optional object1 = Optional.of(1L); + Optional object2 = Optional.empty(); + // When + boolean result1 = Utils.equalsOrNotSet(object1, object2, Optional::isPresent, Optional::get); + boolean result2 = Utils.equalsOrNotSet(object2, object1, Optional::isPresent, Optional::get); + // Then + assertFalse(result1); + assertFalse(result2); + } + + @Test + void equalsOrNotSet_should_throw_exception_when_value_is_null_and_isSet_is_misleading() { + // Given + Optional object1 = Optional.of(1L); + Optional object2 = Optional.empty(); + // When & Then + assertThrows(NoSuchElementException.class, () -> Utils.equalsOrNotSet(object1, object2, o -> true, Optional::get)); + assertThrows(NoSuchElementException.class, () -> Utils.equalsOrNotSet(object2, object1, o -> true, Optional::get)); + } + + @Test + void xpathAttributeFilter_should_succeed() { + // Given + String attributeName = "name"; + String attributeValue = "value"; + // When + String result = Utils.xpathAttributeFilter(attributeName, attributeValue); + // Then + assertEquals("@name=\"value\"", result); + } + + @Test + void xpathAttributeFilter_when_value_is_null_should_succeed() { + // Given + String attributeName = "name"; + String attributeValue = null; + // When + String result = Utils.xpathAttributeFilter(attributeName, attributeValue); + // Then + assertEquals("not(@name)", result); + } + + @Test + void xpathAttributeFilter_when_value_is_collection_should_succeed() { + // Given + String attributeName = "name"; + List attributeValue = List.of("value1", "value2"); + // When + String result = Utils.xpathAttributeFilter(attributeName, attributeValue); + // Then + assertEquals("@name=\"value1 value2\"", result); + } + + @Test + void xpathAttributeFilter_when_value_is_collection_should_ignore_null_values() { + // Given + String attributeName = "name"; + List attributeValue = Arrays.asList(null, "value1", "value2"); + // When + String result = Utils.xpathAttributeFilter(attributeName, attributeValue); + // Then + assertEquals("@name=\"value1 value2\"", result); + } + + @ParameterizedTest + @MethodSource("xpathAttributeFilterEmptyCollectionSource") + void xpathAttributeFilter_when_empty_collection_should_succeed(Collection attributeValue) { + // Given + String attributeName = "name"; + // When + String result = Utils.xpathAttributeFilter(attributeName, attributeValue); + // Then + assertEquals("not(@name)", result); + } + + public static Stream> xpathAttributeFilterEmptyCollectionSource() { + return Stream.of( + null, + Collections.emptyList(), + Arrays.asList(new String[1]), + Arrays.asList(new String[5]) + ); + } +} diff --git a/sct-commons/src/test/resources/scd-refresh-lnode/scd-with-substation-lnode.xml b/sct-commons/src/test/resources/scd-refresh-lnode/scd-with-substation-lnode.xml new file mode 100644 index 000000000..59865ec48 --- /dev/null +++ b/sct-commons/src/test/resources/scd-refresh-lnode/scd-with-substation-lnode.xml @@ -0,0 +1,31 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml b/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml new file mode 100644 index 000000000..59e826a1d --- /dev/null +++ b/sct-commons/src/test/resources/scl-remove-controlBlocks-dataSet-extRefSrc/scl-with-control-blocks.xml @@ -0,0 +1,55 @@ + + + + + + + SSD + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sct-data/pom.xml b/sct-data/pom.xml index 91e9382af..c585ba219 100644 --- a/sct-data/pom.xml +++ b/sct-data/pom.xml @@ -14,7 +14,6 @@ local-SNAPSHOT - org.lfenergy.compas sct-data local-SNAPSHOT SCT-DATA