Skip to content

Commit f1a200d

Browse files
authored
Merge pull request #194 from com-pas/feat/92_filter_FCDA
feat(92): RSR-473 - add check ExtRef is Bay internal and is ExtRef source a Fcda Candidate feat(80): RSR-398 - add service to create DataSet and ControlBlocks part 1
2 parents b653980 + 6d8a5d5 commit f1a200d

38 files changed

+41901
-192
lines changed

sct-app/src/test/java/org.lfenergy.compas.sct.app/SclAutomationServiceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ void createSCD_should_delete_ControlBlocks_DataSet_and_ExtRef_src_attributes() t
146146
// Then
147147
LN0 ln0 = expectedSCD.streamIEDAdapters()
148148
.findFirst()
149-
.map(iedAdapter -> iedAdapter.getLDeviceAdapterByLdInst("lDeviceInst1").orElseThrow())
149+
.map(iedAdapter -> iedAdapter.findLDeviceAdapterByLdInst("lDeviceInst1").orElseThrow())
150150
.map(LDeviceAdapter::getLN0Adapter)
151151
.map(SclElementAdapter::getCurrentElem)
152152
.orElseThrow(() -> new RuntimeException("Test shouldn't fail here, please check your XML input file"));

sct-commons/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<sonar.coverage.jacoco.xmlReportPaths>${basedir}/${aggregate.report.dir}</sonar.coverage.jacoco.xmlReportPaths>
2222
<sonar.jacoco.excludes>**/scl2007b4/**/*</sonar.jacoco.excludes>
2323
<assertJ.version>3.22.0</assertJ.version>
24+
<opencsv.version>5.6</opencsv.version>
2425
<mockito.version>4.9.0</mockito.version>
2526
</properties>
2627

@@ -112,6 +113,11 @@
112113
<version>${assertJ.version}</version>
113114
<scope>test</scope>
114115
</dependency>
116+
<dependency>
117+
<groupId>com.opencsv</groupId>
118+
<artifactId>opencsv</artifactId>
119+
<version>${opencsv.version}</version>
120+
</dependency>
115121
</dependencies>
116122

117123
<build>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public void validateCB() throws ScdException {
105105
public void validateDestination(SclRootAdapter sclRootAdapter) throws ScdException {
106106
for(TControlWithIEDName.IEDName iedName : iedNames){
107107
IEDAdapter iedAdapter =sclRootAdapter.getIEDAdapterByName(iedName.getValue());
108-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(iedName.getLdInst())
108+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(iedName.getLdInst())
109109
.orElseThrow(
110110
() -> new ScdException(
111111
String.format(

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
@NoArgsConstructor
4646
@EqualsAndHashCode
4747
public class DataTypeName {
48+
protected static final String DELIMITER = ".";
49+
4850
protected String name = ""; // dataName or DataAttributeName
4951

5052
private List<String> structNames = new ArrayList<>(); // [.DataName[…]] or [.DAComponentName[ ….]]
@@ -98,13 +100,8 @@ public boolean isDefined(){
98100
*/
99101
@Override
100102
public String toString(){
101-
StringBuilder stringBuilder = new StringBuilder();
102-
stringBuilder.append(name);
103-
for(String sName : structNames){
104-
stringBuilder.append('.');
105-
stringBuilder.append(sName);
106-
}
107-
return stringBuilder.toString();
103+
return name
104+
+ (getStructNames().isEmpty() ? StringUtils.EMPTY : DELIMITER + String.join(DELIMITER, getStructNames()));
108105
}
109106

110107
/**

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import lombok.Getter;
99
import lombok.NoArgsConstructor;
1010
import lombok.Setter;
11+
import org.apache.commons.lang3.StringUtils;
1112
import org.lfenergy.compas.scl2007b4.model.TPredefinedCDCEnum;
13+
import org.lfenergy.compas.sct.commons.util.Utils;
1214

1315
/**
1416
* A representation of the model object <em><b>DoTypeName</b></em>.
@@ -34,6 +36,7 @@ public class DoTypeName extends DataTypeName {
3436

3537
/**
3638
* Constructor
39+
*
3740
* @param doName input
3841
*/
3942
public DoTypeName(String doName) {
@@ -42,6 +45,7 @@ public DoTypeName(String doName) {
4245

4346
/**
4447
* Constructor
48+
*
4549
* @param ppDoName input
4650
* @param sdoNames input
4751
*/
@@ -51,24 +55,39 @@ public DoTypeName(String ppDoName, String sdoNames) {
5155

5256
/**
5357
* Initializes DoTypeName
58+
*
5459
* @param dataName input
5560
* @return DoTypeName object
5661
*/
57-
public static DoTypeName from(DoTypeName dataName){
62+
public static DoTypeName from(DoTypeName dataName) {
5863
DoTypeName doTypeName = new DoTypeName(dataName.toString());
59-
if(doTypeName.isDefined()) {
64+
if (doTypeName.isDefined()) {
6065
doTypeName.setCdc(dataName.getCdc());
6166
}
6267
return doTypeName;
6368
}
6469

6570
/**
6671
* Copy DO's content
72+
*
6773
* @param doName DO object
6874
*/
6975
public void merge(DoTypeName doName) {
70-
if(!isDefined()) return;
71-
if(cdc == null)
76+
if (!isDefined()) return;
77+
if (cdc == null)
7278
cdc = doName.getCdc();
7379
}
80+
81+
/**
82+
* Same as toString() without the instance of the DO.
83+
* Only the DO can have an instance number (not the SDO).
84+
* Prerequisites: A non instanced DO never ends with digits.
85+
*
86+
* @return Same as DataTypeName#toString(), without the digits at the end of the DO if any.
87+
* @see DataTypeName#toString()
88+
*/
89+
public String toStringWithoutInst() {
90+
return Utils.removeTrailingDigits(name)
91+
+ (getStructNames().isEmpty() ? StringUtils.EMPTY : DELIMITER + String.join(DELIMITER, getStructNames()));
92+
}
7493
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
import lombok.AllArgsConstructor;
88
import lombok.EqualsAndHashCode;
99
import lombok.Getter;
10+
import lombok.ToString;
1011

1112
@Getter
1213
@EqualsAndHashCode
1314
@AllArgsConstructor
15+
@ToString
1416
public final class SclReportItem {
1517
private final String xpath;
1618
private final String message;

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

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.lfenergy.compas.scl2007b4.model.TIED;
1212
import org.lfenergy.compas.sct.commons.dto.SclReport;
1313
import org.lfenergy.compas.sct.commons.dto.SclReportItem;
14+
import org.lfenergy.compas.sct.commons.exception.ScdException;
1415
import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
1516
import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter;
1617
import org.lfenergy.compas.sct.commons.scl.ied.LN0Adapter;
@@ -19,10 +20,13 @@
1920
import java.util.*;
2021
import java.util.function.Function;
2122
import java.util.stream.Collectors;
23+
import java.util.stream.Stream;
2224

2325
@UtilityClass
2426
public class ExtRefService {
2527

28+
private static final String MESSAGE_MISSING_IED_NAME_PARAMETER = "IED.name parameter is missing";
29+
2630
/**
2731
* Updates iedName attribute of all ExtRefs in the Scd.
2832
*
@@ -88,12 +92,42 @@ private static List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAd
8892
.filter(entry -> StringUtils.isNotBlank(entry.getKey()))
8993
.filter(entry -> entry.getValue().size() > 1)
9094
.map(entry -> SclReportItem.fatal(entry.getValue().stream()
91-
.map(tied -> new IEDAdapter(sclRootAdapter, tied))
92-
.map(IEDAdapter::getXPath)
93-
.collect(Collectors.joining(", ")),
95+
.map(tied -> new IEDAdapter(sclRootAdapter, tied))
96+
.map(IEDAdapter::getXPath)
97+
.collect(Collectors.joining(", ")),
9498
"/IED/Private/compas:ICDHeader[@ICDSystemVersionUUID] must be unique" +
9599
" but the same ICDSystemVersionUUID was found on several IED."))
96100
.collect(Collectors.toList());
97101
}
98102

103+
public static SclReport createDataSetAndControlBlocks(SCL scd) {
104+
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
105+
Stream<LDeviceAdapter> lDeviceAdapters = sclRootAdapter.streamIEDAdapters().flatMap(IEDAdapter::streamLDeviceAdapters);
106+
return createDataSetAndControlBlocks(sclRootAdapter, lDeviceAdapters);
107+
}
108+
109+
public static SclReport createDataSetAndControlBlocks(SCL scd, String targetIedName) {
110+
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
111+
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
112+
return createDataSetAndControlBlocks(sclRootAdapter, iedAdapter.streamLDeviceAdapters());
113+
114+
}
115+
116+
public static SclReport createDataSetAndControlBlocks(SCL scd, String targetIedName, String targetLDeviceInst) {
117+
if (StringUtils.isBlank(targetIedName)) {
118+
throw new ScdException(MESSAGE_MISSING_IED_NAME_PARAMETER);
119+
}
120+
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
121+
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
122+
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(targetLDeviceInst);
123+
return createDataSetAndControlBlocks(sclRootAdapter, Stream.of(lDeviceAdapter));
124+
}
125+
126+
private static SclReport createDataSetAndControlBlocks(SclRootAdapter sclRootAdapter, Stream<LDeviceAdapter> lDeviceAdapters) {
127+
List<SclReportItem> sclReportItems = lDeviceAdapters
128+
.map(LDeviceAdapter::createDataSetAndControlBlocks)
129+
.flatMap(List::stream)
130+
.collect(Collectors.toList());
131+
return new SclReport(sclRootAdapter, sclReportItems);
132+
}
99133
}

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
1818
import org.lfenergy.compas.sct.commons.scl.sstation.SubstationAdapter;
1919

20+
import java.util.Objects;
21+
import java.util.Optional;
2022
import java.util.stream.Stream;
2123

2224
/**
@@ -59,6 +61,7 @@ public class SclRootAdapter extends SclElementAdapter<SclRootAdapter, SCL> {
5961
public static final short RELEASE = 4;
6062
public static final String REVISION = "B";
6163
public static final String VERSION = "2007";
64+
private static final String MESSAGE_IED_NAME_NOT_FOUND = "IED.name '%s' not found in SCD";
6265

6366
/**
6467
* Constructor
@@ -185,7 +188,7 @@ public IEDAdapter addIED(SCL icd, String iedName) throws ScdException {
185188
throw new ScdException("No IED to import from ICD file");
186189
}
187190

188-
if(hasIED(iedName)){
191+
if(findIedAdapterByName(iedName).isPresent()){
189192
String msg = "SCL file already contains IED: " + iedName;
190193
log.error(msg);
191194
throw new ScdException(msg);
@@ -205,17 +208,6 @@ public IEDAdapter addIED(SCL icd, String iedName) throws ScdException {
205208
return getIEDAdapterByName(iedName);
206209
}
207210

208-
/**
209-
* Checks if IED is present in SCL
210-
* @param iedName name of IED to find in SCL
211-
* @return <em>Boolean</em> value of check result
212-
*/
213-
private boolean hasIED(String iedName) {
214-
return currentElem.getIED()
215-
.stream()
216-
.anyMatch(tied -> tied.getName().equals(iedName));
217-
}
218-
219211
/**
220212
* Gets Header from current SCL
221213
* @return <em>HeaderAdapter</em> object as Header of SCL
@@ -242,8 +234,20 @@ public DataTypeTemplateAdapter getDataTypeTemplateAdapter(){
242234
* @throws ScdException throws when unknown IED
243235
*/
244236
public IEDAdapter getIEDAdapterByName(String iedName) throws ScdException {
245-
// <IED iedNAme></IED> ; Unmarshaller
246-
return new IEDAdapter(this,iedName);
237+
return findIedAdapterByName(iedName)
238+
.orElseThrow(() -> new ScdException(String.format(MESSAGE_IED_NAME_NOT_FOUND, iedName)));
239+
}
240+
241+
/**
242+
* Find an IED by name from SCL
243+
* @param iedName name of IED to find in SCL
244+
* @return <em>Optional<IEDAdapter></em> of the first IED with a matching name
245+
*/
246+
public Optional<IEDAdapter> findIedAdapterByName(String iedName) throws ScdException {
247+
return currentElem.getIED().stream()
248+
.filter(ied -> Objects.equals(ied.getName(), iedName))
249+
.findFirst()
250+
.map(ied -> new IEDAdapter(this, ied));
247251
}
248252

249253
/**

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@
7979
@Slf4j
8080
public class SclService {
8181

82-
public static final String UNKNOWN_LDEVICE_S_IN_IED_S = "Unknown LDevice (%s) in IED (%s)";
83-
public static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info";
84-
public static final ObjectFactory objectFactory = new ObjectFactory();
82+
private static final String UNKNOWN_LDEVICE_S_IN_IED_S = "Unknown LDevice (%s) in IED (%s)";
83+
private static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info";
84+
private static final ObjectFactory objectFactory = new ObjectFactory();
8585

8686
private SclService() {
8787
throw new IllegalStateException("SclService class");
@@ -233,7 +233,7 @@ public static List<ExtRefInfo> getExtRefInfo(SCL scd, String iedName, String ldI
233233

234234
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
235235
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(iedName);
236-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(ldInst)
236+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(ldInst)
237237
.orElseThrow(() -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)));
238238
return lDeviceAdapter.getExtRefInfo();
239239
}
@@ -254,7 +254,7 @@ public static List<ExtRefInfo> getExtRefInfo(SCL scd, String iedName, String ldI
254254
public static List<ExtRefBindingInfo> getExtRefBinders(SCL scd, String iedName, String ldInst, String lnClass, String lnInst, String prefix, ExtRefSignalInfo signalInfo) throws ScdException {
255255
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
256256
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(iedName);
257-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(ldInst)
257+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(ldInst)
258258
.orElseThrow(() -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)));
259259
AbstractLNAdapter<?> abstractLNAdapter = AbstractLNAdapter.builder()
260260
.withLDeviceAdapter(lDeviceAdapter)
@@ -289,7 +289,7 @@ public static void updateExtRefBinders(SCL scd, ExtRefInfo extRefInfo) throws Sc
289289
String ldInst = extRefInfo.getHolderLDInst();
290290
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
291291
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(iedName);
292-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(ldInst)
292+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(ldInst)
293293
.orElseThrow(() -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)));
294294

295295
AbstractLNAdapter<?> abstractLNAdapter = AbstractLNAdapter.builder()
@@ -330,7 +330,7 @@ public static List<ControlBlock<?>> getExtRefSourceInfo(SCL scd, ExtRefInfo extR
330330

331331
// Get CBs
332332
IEDAdapter srcIEDAdapter = sclRootAdapter.getIEDAdapterByName(bindingInfo.getIedName());
333-
LDeviceAdapter srcLDeviceAdapter = srcIEDAdapter.getLDeviceAdapterByLdInst(extRefInfo.getBindingInfo().getLdInst())
333+
LDeviceAdapter srcLDeviceAdapter = srcIEDAdapter.findLDeviceAdapterByLdInst(extRefInfo.getBindingInfo().getLdInst())
334334
.orElseThrow();
335335

336336
List<AbstractLNAdapter<?>> aLNAdapters = srcLDeviceAdapter.getLNAdaptersInclundigLN0();
@@ -375,7 +375,7 @@ public static TExtRef updateExtRefSource(SCL scd, ExtRefInfo extRefInfo) throws
375375

376376
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
377377
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(iedName);
378-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(ldInst)
378+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(ldInst)
379379
.orElseThrow(() -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)));
380380
var anLNAdapter = AbstractLNAdapter.builder()
381381
.withLDeviceAdapter(lDeviceAdapter)
@@ -401,7 +401,7 @@ public static TExtRef updateExtRefSource(SCL scd, ExtRefInfo extRefInfo) throws
401401
public static Set<ResumedDataTemplate> getDAI(SCL scd, String iedName, String ldInst, ResumedDataTemplate rDtt, boolean updatable) throws ScdException {
402402
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
403403
IEDAdapter iedAdapter = new IEDAdapter(sclRootAdapter, iedName);
404-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(ldInst)
404+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(ldInst)
405405
.orElseThrow(() -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)));
406406

407407
return lDeviceAdapter.getDAI(rDtt, updatable);
@@ -433,7 +433,7 @@ public static void updateDAI(SCL scd, String iedName, String ldInst, ResumedData
433433
}
434434

435435
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(iedName);
436-
LDeviceAdapter lDeviceAdapter = iedAdapter.getLDeviceAdapterByLdInst(ldInst)
436+
LDeviceAdapter lDeviceAdapter = iedAdapter.findLDeviceAdapterByLdInst(ldInst)
437437
.orElseThrow(() -> new ScdException(String.format(UNKNOWN_LDEVICE_S_IN_IED_S, ldInst, iedName)));
438438

439439
AbstractLNAdapter<?> lnAdapter = AbstractLNAdapter.builder()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ public TExtRef checkExtRefInfoCoherence(@NonNull ExtRefInfo extRefInfo) throws S
579579
} else {
580580
binderIEDAdapter = getCurrentIed();
581581
}
582-
LDeviceAdapter binderLDAdapter = binderIEDAdapter.getLDeviceAdapterByLdInst(binderLdInst)
582+
LDeviceAdapter binderLDAdapter = binderIEDAdapter.findLDeviceAdapterByLdInst(binderLdInst)
583583
.orElseThrow(
584584
() -> new ScdException(
585585
String.format("Unknown LDevice (%s) in IED (%s)", binderLdInst, binderIedName)

0 commit comments

Comments
 (0)