Skip to content

Commit 545062a

Browse files
committed
feat(84): RSR-433 create datasets from extRef
Signed-off-by: massifben <[email protected]>
1 parent aa6958d commit 545062a

25 files changed

+1050
-307
lines changed

sct-commons/src/main/java/org/lfenergy/compas/sct/commons/dto/FCDAInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public TFCDA getFCDA(){
9494
}
9595

9696
if(doName != null && doName.isDefined()){
97-
tfcda.setDaName(doName.toString());
97+
tfcda.setDoName(doName.toString());
9898
}
9999

100100
if(daName != null && daName.isDefined()){

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static SclReport updateAllExtRefIedNames(SCL scd) {
5353
.filter(LN0Adapter::hasInputs)
5454
.map(LN0Adapter::getInputsAdapter)
5555
.map(inputsAdapter -> inputsAdapter.updateAllExtRefIedNames(icdSystemVersionToIed))
56-
.flatMap(List::stream).collect(Collectors.toList());
56+
.flatMap(List::stream).toList();
5757

5858
return new SclReport(sclRootAdapter, extRefErrors);
5959
}
@@ -79,7 +79,7 @@ private static List<SclReportItem> checkIedCompasIcdHeaderAttributes(SclRootAdap
7979
return null;
8080
}
8181
).filter(Objects::nonNull)
82-
.collect(Collectors.toList());
82+
.toList();
8383
}
8484

8585
private static List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAdapter sclRootAdapter) {
@@ -97,7 +97,7 @@ private static List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAd
9797
.collect(Collectors.joining(", ")),
9898
"/IED/Private/compas:ICDHeader[@ICDSystemVersionUUID] must be unique" +
9999
" but the same ICDSystemVersionUUID was found on several IED."))
100-
.collect(Collectors.toList());
100+
.toList();
101101
}
102102

103103
public static SclReport createDataSetAndControlBlocks(SCL scd) {
@@ -127,7 +127,7 @@ private static SclReport createDataSetAndControlBlocks(SclRootAdapter sclRootAda
127127
List<SclReportItem> sclReportItems = lDeviceAdapters
128128
.map(LDeviceAdapter::createDataSetAndControlBlocks)
129129
.flatMap(List::stream)
130-
.collect(Collectors.toList());
130+
.toList();
131131
return new SclReport(sclRootAdapter, sclReportItems);
132132
}
133133
}

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

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter;
1717
import org.lfenergy.compas.sct.commons.scl.dtt.EnumTypeAdapter;
1818
import org.lfenergy.compas.sct.commons.scl.dtt.LNodeTypeAdapter;
19+
import org.lfenergy.compas.sct.commons.util.ServiceSettingsType;
1920

2021
import java.util.*;
2122
import java.util.stream.Collectors;
@@ -46,7 +47,7 @@
4647
* <li>{@link AbstractLNAdapter#getDAI <em>Returns the value of the <b>ResumedDataTemplate </b> containment reference By filter</em>}</li>
4748
* <li>{@link AbstractLNAdapter#getDAIValues(ResumedDataTemplate) <em>Returns <b>DAI (sGroup, value) </b> containment reference list By <b>ResumedDataTemplate </b> filter</em>}</li>
4849
*
49-
* <li>{@link AbstractLNAdapter#getDataSetByRef(String) <em>Returns the value of the <b>TDataSet </b>object reference By the value of the <b>name </b>attribute </em>}</li>
50+
* <li>{@link AbstractLNAdapter#getDataSetByName(String) <em>Returns the value of the <b>TDataSet </b>object reference By the value of the <b>name </b>attribute </em>}</li>
5051
*
5152
* <li>{@link AbstractLNAdapter#getControlBlocks(List, TServiceType) <em>Returns the value of the <b>ControlBlock </b>containment reference list that match <b>datSet </b> value of given <b>TDataSet</b> </em>}</li>
5253
* <li>{@link AbstractLNAdapter#addPrivate <em>Add <b>TPrivate </b>under this object</em>}</li>
@@ -140,11 +141,12 @@ protected void addControlBlock(ControlBlock<?> controlBlock) throws ScdException
140141
}
141142
}
142143

143-
public Optional<TDataSet> findDataSetByRef(String dataSetRef) {
144+
public Optional<DataSetAdapter> findDataSetByName(String dataSetName) {
144145
return currentElem.getDataSet()
145146
.stream()
146-
.filter(tDataSet -> Objects.equals(tDataSet.getName(), dataSetRef))
147-
.findFirst();
147+
.filter(tDataSet -> Objects.equals(tDataSet.getName(), dataSetName))
148+
.findFirst()
149+
.map(dataSet -> new DataSetAdapter(this, dataSet));
148150
}
149151

150152
public DOIAdapter getDOIAdapterByName(String doiName) throws ScdException {
@@ -345,9 +347,8 @@ public List<ControlBlock<?>> getControlBlocksForMatchingFCDA(@NonNull ExtRefInfo
345347
*/
346348
protected List<ControlBlock<?>> getControlBlocks(List<TDataSet> tDataSets, TServiceType serviceType) {
347349
return tDataSets.stream()
348-
.map(tDataSet -> getControlBlocksByDataSetRef(tDataSet.getName(), serviceType))
349-
.flatMap(Collection::stream).toList();
350-
350+
.map(tDataSet -> getControlBlocksByDataSetRef(tDataSet.getName(), serviceType))
351+
.flatMap(Collection::stream).toList();
351352
}
352353

353354
/**
@@ -655,14 +656,22 @@ private boolean iedHasConfSG() {
655656
return iedAdapter.isSettingConfig(this.parentAdapter.getInst());
656657
}
657658

659+
/**
660+
* Gets linked LDevice as parent
661+
*
662+
* @return <em>IEDAdapter</em> object
663+
*/
664+
private LDeviceAdapter getCurrentLDevice() {
665+
return this.parentAdapter;
666+
}
667+
658668
/**
659669
* Gets linked IED as parent
660670
*
661671
* @return <em>IEDAdapter</em> object
662672
*/
663673
private IEDAdapter getCurrentIed() {
664-
LDeviceAdapter lDeviceAdapter = this.parentAdapter;
665-
return lDeviceAdapter.getParentAdapter();
674+
return getCurrentLDevice().getParentAdapter();
666675
}
667676

668677
/**
@@ -854,32 +863,17 @@ protected boolean matchesDataAttributes(String dataAttribute) {
854863
/**
855864
* Gets Data Set in LNode by its name
856865
*
857-
* @param dataSetRef Data Set name
866+
* @param dataSetName Data Set name
858867
* @return optional of <em>DataSetInfo</em>
859868
*/
860-
public Optional<DataSetInfo> getDataSetByRef(String dataSetRef) {
869+
public Optional<DataSetInfo> getDataSetByName(String dataSetName) {
861870
return currentElem.getDataSet()
862871
.stream()
863-
.filter(tDataSet -> tDataSet.getName().equals(dataSetRef))
872+
.filter(tDataSet -> tDataSet.getName().equals(dataSetName))
864873
.map(DataSetInfo::from)
865874
.findFirst();
866875
}
867876

868-
/**
869-
* Adds Data Set to LNode Data Sets
870-
*
871-
* @param dataSetInfo data's of Data Set to add
872-
*/
873-
public void addDataSet(DataSetInfo dataSetInfo) {
874-
TDataSet tDataSet = new TDataSet();
875-
tDataSet.setName(dataSetInfo.getName());
876-
tDataSet.getFCDA().addAll(
877-
dataSetInfo.getFCDAInfos().stream().map(FCDAInfo::getFCDA).toList()
878-
);
879-
currentElem.getDataSet().add(tDataSet);
880-
881-
}
882-
883877
/**
884878
* Gets DAI values for specified DA in summaraized Data Type Template
885879
*
@@ -939,4 +933,25 @@ private void removeExtRefSourceBinding(final TExtRef tExtRef) {
939933
tExtRef.unsetSrcLNClass();
940934
}
941935

936+
/**
937+
* Adds DataSet in specified LNode in current IED/AccessPoint.
938+
* The AccessPoint must have DataSet creation capabilities
939+
*
940+
* @param dataSetName Name of the dataSet
941+
* @param serviceSettingsType GOOSE, SMV or REPORT service type
942+
* @throws ScdException throws when IED does not have DataSet creation capabilities
943+
* @see LDeviceAdapter#hasDataSetCreationCapability
944+
*/
945+
public DataSetAdapter createDataSetIfNotExists(String dataSetName, ServiceSettingsType serviceSettingsType) {
946+
return findDataSetByName(dataSetName).orElseGet(() -> {
947+
if (!getCurrentLDevice().hasDataSetCreationCapability(serviceSettingsType)) {
948+
throw new ScdException("IED/AccessPoint does not have capability to create DataSet of type %s in %s"
949+
.formatted(serviceSettingsType, getXPath()));
950+
}
951+
TDataSet newDataSet = new TDataSet();
952+
newDataSet.setName(dataSetName);
953+
currentElem.getDataSet().add(newDataSet);
954+
return new DataSetAdapter(this, newDataSet);
955+
});
956+
}
942957
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// SPDX-FileCopyrightText: 2022 RTE FRANCE
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.sct.commons.scl.ied;
6+
7+
8+
import org.apache.commons.lang3.StringUtils;
9+
import org.lfenergy.compas.scl2007b4.model.TAnyLN;
10+
import org.lfenergy.compas.scl2007b4.model.TDataSet;
11+
import org.lfenergy.compas.scl2007b4.model.TFCDA;
12+
import org.lfenergy.compas.scl2007b4.model.TFCEnum;
13+
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
14+
import org.lfenergy.compas.sct.commons.util.Utils;
15+
16+
import java.util.Comparator;
17+
import java.util.Objects;
18+
import java.util.Optional;
19+
20+
import static org.lfenergy.compas.sct.commons.util.Utils.*;
21+
22+
/**
23+
* A representation of the model object
24+
* <em><b>{@link DataSetAdapter DataSetAdapter}</b></em>.
25+
* <p>
26+
* The following features are supported:
27+
* </p>
28+
* <ol>
29+
* <li>Principal functions</li>
30+
* <ul>
31+
* <li>{@link DataSetAdapter#findFCDA <em>look for a FCDA in this DataSet</em>}</li>
32+
* <li>{@link DataSetAdapter#createFCDAIfNotExists <em>create a FCDA in this DataSet</em></li>
33+
* </ul>
34+
* </ol>
35+
* <br/>
36+
* <pre>
37+
* <b>ObjectReference</b>: DataSet
38+
* <b>LDName</b> = "name" key of the DataSet in the parent LN/LN0
39+
* </pre>
40+
*
41+
* @see TLN0
42+
* @see AbstractLNAdapter
43+
*/
44+
public class DataSetAdapter extends SclElementAdapter<AbstractLNAdapter<? extends TAnyLN>, TDataSet> {
45+
46+
/**
47+
* IEC 61850 requires FCDA to be oredred inside a DataSet.
48+
* This is the comparator to sort the FCDA inside a DataSet
49+
*/
50+
private static final Comparator<TFCDA> fcdaComparator = Comparator
51+
.comparing(TFCDA::getLdInst, Utils::blanksFirstComparator)
52+
.thenComparing(TFCDA::getPrefix, Utils::blanksFirstComparator)
53+
.thenComparing(tfcda -> tfcda.isSetLnClass() ? tfcda.getLnClass().get(0) : null, Utils::blanksFirstComparator)
54+
.thenComparing(tfcda -> tfcda.getLnInst() != null ? Integer.valueOf(tfcda.getLnInst()) : null, Comparator.nullsFirst(Integer::compareTo))
55+
.thenComparing(TFCDA::getDoName, Utils::blanksFirstComparator)
56+
.thenComparing(TFCDA::getDaName, Utils::blanksFirstComparator);
57+
58+
public DataSetAdapter(AbstractLNAdapter<? extends TAnyLN> parentAdapter, TDataSet dataSet) {
59+
super(parentAdapter, dataSet);
60+
}
61+
62+
/**
63+
* Check if node is child of the reference node
64+
*
65+
* @return link parent child existence
66+
*/
67+
@Override
68+
protected boolean amChildElementRef() {
69+
return parentAdapter.getCurrentElem().isSetDataSet() && parentAdapter.getCurrentElem().getDataSet().stream().anyMatch(dataSet ->
70+
Objects.equals(currentElem.getName(), dataSet.getName()));
71+
}
72+
73+
/**
74+
* Returns local XPath
75+
* @return XPath for current element (not including parent XPath)
76+
*/
77+
@Override
78+
protected String elementXPath() {
79+
return String.format("DataSet[%s]", xpathAttributeFilter("name", currentElem.getName()));
80+
}
81+
82+
/**
83+
* Find a FCDA matching all given criteria.
84+
* @param ldInst FCDA ldInst attribute
85+
* @param prefix FCDA prefix attribute
86+
* @param lnClass FCDA lnClass attribute
87+
* @param lnInst FCDA lnInst attribute
88+
* @param doName FCDA doName attribute
89+
* @param daName FCDA daNae attribute
90+
* @param fc FCDA fc attribute
91+
* @return Matching FCDA in this DataSet when found, empty Optional otherwise.
92+
*/
93+
public Optional<TFCDA> findFCDA(String ldInst, String prefix, String lnClass, String lnInst, String doName, String daName, TFCEnum fc) {
94+
if (!currentElem.isSetFCDA()) {
95+
return Optional.empty();
96+
}
97+
return currentElem.getFCDA().stream()
98+
.filter(tfcda ->
99+
Objects.equals(ldInst, tfcda.getLdInst())
100+
&& equalsOrBothBlank(prefix, tfcda.getPrefix())
101+
&& tfcda.getLnClass().contains(lnClass)
102+
&& equalsOrBothBlank(lnInst, tfcda.getLnInst())
103+
&& Objects.equals(doName, tfcda.getDoName())
104+
&& Objects.equals(fc, tfcda.getFc())
105+
&& equalsOrBothBlank(daName, tfcda.getDaName()))
106+
.findFirst();
107+
}
108+
109+
/**
110+
* Create a new FCDA in this DataSet.
111+
* Does nothing if a FCDA with the given attribute already exists in this DataSet.
112+
* @param ldInst FCDA ldInst attribute
113+
* @param prefix FCDA prefix attribute
114+
* @param lnClass FCDA lnClass attribute
115+
* @param lnInst FCDA lnInst attribute
116+
* @param doName FCDA doName attribute
117+
* @param daName FCDA daNae attribute
118+
* @param fc FCDA fc attribute
119+
* @return created FCDA, or existing FCDA with the given attributes
120+
*/
121+
public TFCDA createFCDAIfNotExists(String ldInst, String prefix, String lnClass, String lnInst, String doName, String daName, TFCEnum fc) {
122+
Objects.requireNonNull(fc); // fc is required by XSD
123+
Optional<TFCDA> fcda = findFCDA(ldInst, prefix, lnClass, lnInst, doName, daName, fc);
124+
return fcda
125+
.orElseGet(() -> {
126+
TFCDA newFcda = new TFCDA();
127+
newFcda.setLdInst(nullIfBlank(ldInst));
128+
newFcda.setPrefix(nullIfBlank(prefix));
129+
if (StringUtils.isNotBlank(lnClass)) {
130+
newFcda.getLnClass().add(lnClass);
131+
}
132+
newFcda.setLnInst(nullIfBlank(lnInst));
133+
newFcda.setDoName(nullIfBlank(doName));
134+
newFcda.setDaName(nullIfBlank(daName));
135+
newFcda.setFc(fc);
136+
currentElem.getFCDA().add(newFcda);
137+
currentElem.getFCDA().sort(fcdaComparator);
138+
return newFcda;
139+
});
140+
}
141+
142+
}

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

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import org.apache.commons.lang3.StringUtils;
99
import org.lfenergy.compas.scl2007b4.model.*;
1010
import org.lfenergy.compas.sct.commons.dto.ControlBlock;
11-
import org.lfenergy.compas.sct.commons.dto.DataSetInfo;
1211
import org.lfenergy.compas.sct.commons.dto.ExtRefBindingInfo;
1312
import org.lfenergy.compas.sct.commons.dto.ExtRefSignalInfo;
1413
import org.lfenergy.compas.sct.commons.exception.ScdException;
@@ -44,7 +43,6 @@
4443
* <li>{@link IEDAdapter#getServices Returns the value of the <b>Service </b>object</em>}</li>
4544
* <li>{@link IEDAdapter#getPrivateHeader <em>Returns the value of the <b>TPrivate </b>containment reference list</em>}</li>
4645
* <li>{@link IEDAdapter#getExtRefBinders <em>Returns the value of the <b>ExtRefBindingInfo </b>containment reference list By <b>ExtRefSignalInfo</b></em>}</li>
47-
* <li>{@link IEDAdapter#createDataSet <em>Add <b>DataSetInfo </b> describing the children <b>TDataSet </b> that can be created under <b>TAnyLN</b></em>}</li>
4846
* <li>{@link IEDAdapter#createControlBlock <em>Add <b>ControlBlock </b> describing the children <b>TControlBlock </b> that can be created under <b>TAnyLN</b></em>}</li>
4947
* <li>{@link IEDAdapter#addPrivate <em>Add <b>TPrivate </b>under this object</em>}</li>
5048
* <li>{@link IEDAdapter#updateLDeviceNodesType <em>Update <b>Type </b> describing the value of the children <b>TAnyLN</b></em>}</li>
@@ -304,33 +302,6 @@ public boolean isSettingConfig(String ldInst) {
304302
return srv != null && srv.getSettingGroups() != null && srv.getSettingGroups().getConfSG() != null;
305303
}
306304

307-
/**
308-
* Adds Data Set in specified LNode in current IED
309-
*
310-
* @param dataSetInfo Data Set data to add (and LNode path)
311-
* @param serviceSettingsType Type of DataSet to create
312-
* @throws ScdException throws when IED is not able to add DataSet
313-
*/
314-
public void createDataSet(DataSetInfo dataSetInfo, ServiceSettingsType serviceSettingsType) throws ScdException {
315-
LDeviceAdapter lDeviceAdapter = findLDeviceAdapterByLdInst(dataSetInfo.getHolderLDInst())
316-
.orElseThrow(
317-
() -> new ScdException(
318-
String.format(
319-
"Unknow LDevice(%s) in IED(%s)", dataSetInfo.getHolderLDInst(), currentElem.getName())
320-
)
321-
);
322-
if (!lDeviceAdapter.hasDataSetCreationCapability(serviceSettingsType)) {
323-
throw new ScdException("The AccessPoint does not have capability to create DataSet of type " + serviceSettingsType.toString());
324-
}
325-
AbstractLNAdapter<?> lNodeAdapter = AbstractLNAdapter.builder()
326-
.withLDeviceAdapter(lDeviceAdapter)
327-
.withLnClass(dataSetInfo.getHolderLnClass())
328-
.withLnInst(dataSetInfo.getHolderLnInst())
329-
.withLnPrefix(dataSetInfo.getHolderLnPrefix())
330-
.build();
331-
lNodeAdapter.addDataSet(dataSetInfo);
332-
}
333-
334305
/**
335306
* Creates Control Block in specified LNode in current IED
336307
*
@@ -366,7 +337,7 @@ public ControlBlock<? extends ControlBlock> createControlBlock(ControlBlock<? ex
366337
);
367338
}
368339

369-
if (lnAdapter.getDataSetByRef(controlBlock.getDataSetRef()).isEmpty()) {
340+
if (lnAdapter.getDataSetByName(controlBlock.getDataSetRef()).isEmpty()) {
370341
throw new ScdException(
371342
String.format(
372343
"Control block %s references unknown dataSet in LNode %s%s%s",

0 commit comments

Comments
 (0)