Skip to content

Commit 2258b1a

Browse files
authored
Merge pull request #255 from com-pas/develop
Merge branch develop into main
2 parents be542e2 + 6a5da6b commit 2258b1a

File tree

73 files changed

+2624
-562
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+2624
-562
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<sonar.coverage.exclusions>sct-coverage/**</sonar.coverage.exclusions>
3838
<aggregate.report.dir>../sct-coverage/target/site/jacoco-aggregate/jacoco.xml</aggregate.report.dir>
3939
<sonar.coverage.jacoco.xmlReportPaths>${basedir}/${aggregate.report.dir}</sonar.coverage.jacoco.xmlReportPaths>
40-
<compas-core.version>0.12.0</compas-core.version>
40+
<compas-core.version>0.13.0</compas-core.version>
4141
<compas-scl-xsd.version>0.0.4</compas-scl-xsd.version>
4242
<maven.plugin.javadoc>3.4.1</maven.plugin.javadoc>
4343
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-FileCopyrightText: 2023 RTE FRANCE
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.sct.commons.dto;
6+
7+
import org.lfenergy.compas.scl2007b4.model.TDurationInMilliSec;
8+
import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
9+
10+
/**
11+
* This interface has a single method which provides network settings for a ControlBlock.
12+
* These are used to create:
13+
* - the Communication/SubNetwork/ConnectedAP/GSE element, which is the network configuration of a GSEControl block
14+
* - the Communication/SubNetwork/ConnectedAP/SMV element, which is the network configuration of a SampledValueControl block
15+
* It is a FunctionalInterface, so it can be implemented with a lambda expression.
16+
*
17+
* @see org.lfenergy.compas.sct.commons.util.ControlBlockNetworkSettingsCsvHelper
18+
*/
19+
@FunctionalInterface
20+
public interface ControlBlockNetworkSettings {
21+
22+
/**
23+
* This method provides a vlanId, vlanPriority, minTime, maxTime for this ControlBlock.
24+
* vlanPriority will be ignored when vlanId is null.
25+
*
26+
* @param controlBlockAdapter ControlBlock for which we want to configure the communication section
27+
* @return network settings : All fields are optional (meaning fields can be null).
28+
* When the return value itself is null, the communication section will not be configured for this ControlBlock.
29+
*/
30+
Settings getNetworkSettings(ControlBlockAdapter controlBlockAdapter);
31+
32+
/**
33+
* Network settings for ControlBlock communication
34+
*
35+
* @param vlanId id of the vlan
36+
* @param vlanPriority priority for the vlan
37+
* @param minTime minTime for GSE communication element
38+
* @param maxTime maxTime for GSE communication element
39+
*/
40+
record Settings(Integer vlanId, Byte vlanPriority, TDurationInMilliSec minTime, TDurationInMilliSec maxTime) {
41+
}
42+
43+
/**
44+
* NetworkRanges for GSEControl and SampledValueControl
45+
*
46+
* @param gse NetworkRanges for GSEControl
47+
* @param sampledValue NetworkRanges for SampledValueControl
48+
*/
49+
record RangesPerCbType(NetworkRanges gse, NetworkRanges sampledValue) {
50+
}
51+
52+
/**
53+
* Range of APPID and range of MAC-Address
54+
*
55+
* @param appIdStart range start for APPID (inclusive)
56+
* @param appIdEnd range end for APPID (inclusive)
57+
* @param macAddressStart range start for MAC-Addresses (inclusive). Ex: "01-0C-CD-01-00-00"
58+
* @param macAddressEnd range end for MAC-Addresses (inclusive). Ex: "01-0C-CD-01-01-FF"
59+
*/
60+
record NetworkRanges(long appIdStart, long appIdEnd, String macAddressStart, String macAddressEnd) {
61+
}
62+
}

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

Lines changed: 136 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,31 @@
99
import org.lfenergy.compas.scl2007b4.model.SCL;
1010
import org.lfenergy.compas.scl2007b4.model.TCompasICDHeader;
1111
import org.lfenergy.compas.scl2007b4.model.TIED;
12+
import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings;
13+
import org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.Settings;
1214
import org.lfenergy.compas.sct.commons.dto.SclReport;
1315
import org.lfenergy.compas.sct.commons.dto.SclReportItem;
1416
import org.lfenergy.compas.sct.commons.exception.ScdException;
17+
import org.lfenergy.compas.sct.commons.scl.ied.ControlBlockAdapter;
1518
import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
1619
import org.lfenergy.compas.sct.commons.scl.ied.LDeviceAdapter;
1720
import org.lfenergy.compas.sct.commons.scl.ied.LN0Adapter;
21+
import org.lfenergy.compas.sct.commons.util.ControlBlockEnum;
1822
import org.lfenergy.compas.sct.commons.util.PrivateEnum;
23+
import org.lfenergy.compas.sct.commons.util.Utils;
1924

2025
import java.util.*;
2126
import java.util.function.Function;
2227
import java.util.stream.Collectors;
2328
import java.util.stream.Stream;
2429

30+
import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.NetworkRanges;
31+
import static org.lfenergy.compas.sct.commons.dto.ControlBlockNetworkSettings.RangesPerCbType;
32+
2533
@UtilityClass
2634
public class ExtRefService {
2735

2836
private static final String MESSAGE_MISSING_IED_NAME_PARAMETER = "IED.name parameter is missing";
29-
private static final String CLIENT_IED_NAME = "The Client IED ";
3037

3138
/**
3239
* Updates iedName attribute of all ExtRefs in the Scd.
@@ -40,21 +47,21 @@ public static SclReport updateAllExtRefIedNames(SCL scd) {
4047
return new SclReport(sclRootAdapter, iedErrors);
4148
}
4249
Map<String, IEDAdapter> icdSystemVersionToIed = sclRootAdapter.streamIEDAdapters()
43-
.collect(Collectors.toMap(
44-
iedAdapter -> PrivateService.extractCompasPrivate(iedAdapter.getCurrentElem(), TCompasICDHeader.class)
45-
.map(TCompasICDHeader::getICDSystemVersionUUID)
46-
.orElseThrow(), // Value presence is checked by method validateIed called above
47-
Function.identity()
48-
));
50+
.collect(Collectors.toMap(
51+
iedAdapter -> iedAdapter.getCompasICDHeader()
52+
.map(TCompasICDHeader::getICDSystemVersionUUID)
53+
.orElseThrow(), // Value presence is checked by method validateIed called above
54+
Function.identity()
55+
));
4956

5057
List<SclReportItem> extRefErrors = sclRootAdapter.streamIEDAdapters()
51-
.flatMap(IEDAdapter::streamLDeviceAdapters)
52-
.filter(LDeviceAdapter::hasLN0)
53-
.map(LDeviceAdapter::getLN0Adapter)
54-
.filter(LN0Adapter::hasInputs)
55-
.map(LN0Adapter::getInputsAdapter)
56-
.map(inputsAdapter -> inputsAdapter.updateAllExtRefIedNames(icdSystemVersionToIed))
57-
.flatMap(List::stream).toList();
58+
.flatMap(IEDAdapter::streamLDeviceAdapters)
59+
.filter(LDeviceAdapter::hasLN0)
60+
.map(LDeviceAdapter::getLN0Adapter)
61+
.filter(LN0Adapter::hasInputs)
62+
.map(LN0Adapter::getInputsAdapter)
63+
.map(inputsAdapter -> inputsAdapter.updateAllExtRefIedNames(icdSystemVersionToIed))
64+
.flatMap(List::stream).toList();
5865

5966
return new SclReport(sclRootAdapter, extRefErrors);
6067
}
@@ -67,53 +74,74 @@ private static List<SclReportItem> validateIed(SclRootAdapter sclRootAdapter) {
6774

6875
private static List<SclReportItem> checkIedCompasIcdHeaderAttributes(SclRootAdapter sclRootAdapter) {
6976
return sclRootAdapter.streamIEDAdapters()
70-
.map(iedAdapter -> {
71-
Optional<TCompasICDHeader> compasPrivate = PrivateService.extractCompasPrivate(iedAdapter.getCurrentElem(), TCompasICDHeader.class);
72-
if (compasPrivate.isEmpty()) {
73-
return iedAdapter.buildFatalReportItem(String.format("IED has no Private %s element", PrivateEnum.COMPAS_ICDHEADER.getPrivateType()));
74-
}
75-
if (StringUtils.isBlank(compasPrivate.get().getICDSystemVersionUUID())
76-
|| StringUtils.isBlank(compasPrivate.get().getIEDName())) {
77-
return iedAdapter.buildFatalReportItem(String.format("IED private %s as no icdSystemVersionUUID or iedName attribute",
78-
PrivateEnum.COMPAS_ICDHEADER.getPrivateType()));
79-
}
80-
return null;
81-
}
82-
).filter(Objects::nonNull)
83-
.toList();
77+
.map(iedAdapter -> {
78+
Optional<TCompasICDHeader> compasPrivate = iedAdapter.getCompasICDHeader();
79+
if (compasPrivate.isEmpty()) {
80+
return iedAdapter.buildFatalReportItem(String.format("IED has no Private %s element", PrivateEnum.COMPAS_ICDHEADER.getPrivateType()));
81+
}
82+
if (StringUtils.isBlank(compasPrivate.get().getICDSystemVersionUUID())
83+
|| StringUtils.isBlank(compasPrivate.get().getIEDName())) {
84+
return iedAdapter.buildFatalReportItem(String.format("IED private %s as no icdSystemVersionUUID or iedName attribute",
85+
PrivateEnum.COMPAS_ICDHEADER.getPrivateType()));
86+
}
87+
return null;
88+
}
89+
).filter(Objects::nonNull)
90+
.toList();
8491
}
8592

8693
private static List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAdapter sclRootAdapter) {
8794
Map<String, List<TIED>> systemVersionToIedList = sclRootAdapter.getCurrentElem().getIED().stream()
88-
.collect(Collectors.groupingBy(ied -> PrivateService.extractCompasPrivate(ied, TCompasICDHeader.class)
89-
.map(TCompasICDHeader::getICDSystemVersionUUID)
90-
.orElse("")));
95+
.collect(Collectors.groupingBy(ied -> PrivateService.extractCompasPrivate(ied, TCompasICDHeader.class)
96+
.map(TCompasICDHeader::getICDSystemVersionUUID)
97+
.orElse("")));
9198

9299
return systemVersionToIedList.entrySet().stream()
93-
.filter(entry -> StringUtils.isNotBlank(entry.getKey()))
94-
.filter(entry -> entry.getValue().size() > 1)
95-
.map(entry -> SclReportItem.fatal(entry.getValue().stream()
96-
.map(tied -> new IEDAdapter(sclRootAdapter, tied))
97-
.map(IEDAdapter::getXPath)
98-
.collect(Collectors.joining(", ")),
99-
"/IED/Private/compas:ICDHeader[@ICDSystemVersionUUID] must be unique" +
100-
" but the same ICDSystemVersionUUID was found on several IED."))
101-
.toList();
100+
.filter(entry -> StringUtils.isNotBlank(entry.getKey()))
101+
.filter(entry -> entry.getValue().size() > 1)
102+
.map(entry -> SclReportItem.fatal(entry.getValue().stream()
103+
.map(tied -> new IEDAdapter(sclRootAdapter, tied))
104+
.map(IEDAdapter::getXPath)
105+
.collect(Collectors.joining(", ")),
106+
"/IED/Private/compas:ICDHeader[@ICDSystemVersionUUID] must be unique" +
107+
" but the same ICDSystemVersionUUID was found on several IED."))
108+
.toList();
102109
}
103110

111+
/**
112+
* Create All DataSet and ControlBlock in the SCL based on the ExtRef
113+
*
114+
* @param scd input SCD object. It could be modified by adding new DataSet and ControlBlocks
115+
* @return a report with all errors encountered
116+
*/
104117
public static SclReport createDataSetAndControlBlocks(SCL scd) {
105118
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
106119
Stream<LDeviceAdapter> lDeviceAdapters = sclRootAdapter.streamIEDAdapters().flatMap(IEDAdapter::streamLDeviceAdapters);
107120
return createDataSetAndControlBlocks(sclRootAdapter, lDeviceAdapters);
108121
}
109122

123+
/**
124+
* Create All DataSet and ControlBlock for the ExtRef in given IED
125+
*
126+
* @param scd input SCD object. The object will be modified with the new DataSet and ControlBlocks
127+
* @param targetIedName the name of the IED where the ExtRef are
128+
* @return a report with all the errors encountered
129+
*/
110130
public static SclReport createDataSetAndControlBlocks(SCL scd, String targetIedName) {
111131
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
112132
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName(targetIedName);
113133
return createDataSetAndControlBlocks(sclRootAdapter, iedAdapter.streamLDeviceAdapters());
114134

115135
}
116136

137+
/**
138+
* Create All DataSet and ControlBlock for the ExtRef in this LDevice
139+
*
140+
* @param scd input SCD object. The object will be modified with the new DataSet and ControlBlocks
141+
* @param targetIedName the name of the IED where the ExtRef are
142+
* @param targetLDeviceInst the name of the LDevice where the ExtRef are
143+
* @return a report with all encountered errors
144+
*/
117145
public static SclReport createDataSetAndControlBlocks(SCL scd, String targetIedName, String targetLDeviceInst) {
118146
if (StringUtils.isBlank(targetIedName)) {
119147
throw new ScdException(MESSAGE_MISSING_IED_NAME_PARAMETER);
@@ -126,9 +154,74 @@ public static SclReport createDataSetAndControlBlocks(SCL scd, String targetIedN
126154

127155
private static SclReport createDataSetAndControlBlocks(SclRootAdapter sclRootAdapter, Stream<LDeviceAdapter> lDeviceAdapters) {
128156
List<SclReportItem> sclReportItems = lDeviceAdapters
129-
.map(LDeviceAdapter::createDataSetAndControlBlocks)
130-
.flatMap(List::stream)
131-
.toList();
157+
.map(LDeviceAdapter::createDataSetAndControlBlocks)
158+
.flatMap(List::stream)
159+
.toList();
132160
return new SclReport(sclRootAdapter, sclReportItems);
133161
}
162+
163+
/**
164+
* Configure the network for all the ControlBlocks.
165+
* Create (or update if already existing) these elements
166+
* - the Communication/SubNetwork/ConnectedAP/GSE element, for the GSEControl blocks
167+
* - the Communication/SubNetwork/ConnectedAP/SMV element, for the SampledValueControl blocks
168+
*
169+
* @param scd input SCD object. The object will be modified with the new DataGSESet and SMV elements
170+
* @param controlBlockNetworkSettings a method tha gives the network configuration information for a given ControlBlock
171+
* @param rangesPerCbType provide NetworkRanges for GSEControl and SampledValueControl. NetworkRanges contains :
172+
* start-end app APPID range (long value), start-end MAC-Addresses (Mac-Addresses values: Ex: "01-0C-CD-01-01-FF")
173+
* @return a report with all the errors encountered
174+
* @see Utils#macAddressToLong(String) for the expected MAC address format
175+
* @see ControlBlockNetworkSettings
176+
* @see ControlBlockNetworkSettings.RangesPerCbType
177+
* @see ControlBlockNetworkSettings.NetworkRanges
178+
*/
179+
public static SclReport configureNetworkForAllControlBlocks(SCL scd, ControlBlockNetworkSettings controlBlockNetworkSettings,
180+
RangesPerCbType rangesPerCbType) {
181+
List<SclReportItem> sclReportItems = new ArrayList<>();
182+
sclReportItems.addAll(configureNetworkForControlBlocks(scd, controlBlockNetworkSettings, rangesPerCbType.gse(), ControlBlockEnum.GSE));
183+
sclReportItems.addAll(configureNetworkForControlBlocks(scd, controlBlockNetworkSettings, rangesPerCbType.sampledValue(), ControlBlockEnum.SAMPLED_VALUE));
184+
return new SclReport(new SclRootAdapter(scd), sclReportItems);
185+
}
186+
187+
private static List<SclReportItem> configureNetworkForControlBlocks(SCL scd, ControlBlockNetworkSettings controlBlockNetworkSettings,
188+
NetworkRanges networkRanges, ControlBlockEnum controlBlockEnum) {
189+
PrimitiveIterator.OfLong appIdIterator = Utils.sequence(networkRanges.appIdStart(), networkRanges.appIdEnd());
190+
Iterator<String> macAddressIterator = Utils.macAddressSequence(networkRanges.macAddressStart(), networkRanges.macAddressEnd());
191+
192+
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
193+
return sclRootAdapter.streamIEDAdapters()
194+
.flatMap(iedAdapter ->
195+
iedAdapter.streamLDeviceAdapters()
196+
.filter(LDeviceAdapter::hasLN0)
197+
.map(LDeviceAdapter::getLN0Adapter)
198+
.flatMap(ln0Adapter -> ln0Adapter.streamControlBlocks(controlBlockEnum))
199+
.map(controlBlockAdapter -> configureControlBlockNetwork(controlBlockNetworkSettings, appIdIterator, macAddressIterator, controlBlockAdapter)))
200+
.flatMap(Optional::stream)
201+
.toList();
202+
}
203+
204+
private static Optional<SclReportItem> configureControlBlockNetwork(ControlBlockNetworkSettings controlBlockNetworkSettings, PrimitiveIterator.OfLong appIdIterator, Iterator<String> macAddressIterator, ControlBlockAdapter controlBlockAdapter) {
205+
Settings settings = controlBlockNetworkSettings.getNetworkSettings(controlBlockAdapter);
206+
207+
if (settings == null) {
208+
return Optional.of(controlBlockAdapter.buildFatalReportItem(
209+
"Cannot configure network for this ControlBlock because no settings was provided"));
210+
}
211+
if (settings.vlanId() == null) {
212+
return Optional.of(controlBlockAdapter.buildFatalReportItem(
213+
"Cannot configure network for this ControlBlock because no Vlan Id was provided in the settings"));
214+
}
215+
if (!appIdIterator.hasNext()) {
216+
return Optional.of(controlBlockAdapter.buildFatalReportItem(
217+
"Cannot configure network for this ControlBlock because range of appId is exhausted"));
218+
}
219+
if (!macAddressIterator.hasNext()) {
220+
return Optional.of(controlBlockAdapter.buildFatalReportItem(
221+
"Cannot configure network for this ControlBlock because range of MAC Address is exhausted"));
222+
}
223+
224+
return controlBlockAdapter.configureNetwork(appIdIterator.nextLong(), macAddressIterator.next(), settings.vlanId(), settings.vlanPriority(),
225+
settings.minTime(), settings.maxTime());
226+
}
134227
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.lfenergy.compas.scl2007b4.model.*;
1313
import org.lfenergy.compas.sct.commons.exception.ScdException;
1414
import org.lfenergy.compas.sct.commons.scl.com.CommunicationAdapter;
15+
import org.lfenergy.compas.sct.commons.scl.com.ConnectedAPAdapter;
1516
import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter;
1617
import org.lfenergy.compas.sct.commons.scl.header.HeaderAdapter;
1718
import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
@@ -291,4 +292,20 @@ public IEDAdapter checkObjRef(String val) throws ScdException {
291292
throw new ScdException("Invalid ObjRef: " + val);
292293
}
293294

295+
/**
296+
* Find a ConnectedAp element withe given iedName and apName
297+
* @param iedName iedName
298+
* @param apName apName
299+
* @return the first ConnectedAp which match the given iedName and apName, or empty Optional if none found
300+
*/
301+
public Optional<ConnectedAPAdapter> findConnectedApAdapter(String iedName, String apName) {
302+
if (!currentElem.isSetCommunication()) {
303+
return Optional.empty();
304+
}
305+
CommunicationAdapter communicationAdapter = new CommunicationAdapter(this, currentElem.getCommunication());
306+
return communicationAdapter.getSubNetworkAdapters().stream()
307+
.map(subNetworkAdapter -> subNetworkAdapter.findConnectedAPAdapter(iedName, apName))
308+
.flatMap(Optional::stream)
309+
.findFirst();
310+
}
294311
}

0 commit comments

Comments
 (0)