Skip to content

Commit 20eefae

Browse files
authored
feat(#605): RSR-1590 - IED Capacity - SCL/IED/Services (#606)
* feat(#605): IED Capacity - SCL/IED/Services Signed-off-by: redaneuhaus <242222272+redaneuhaus@users.noreply.github.com>
1 parent 31b245c commit 20eefae

8 files changed

Lines changed: 94 additions & 96 deletions

File tree

sct-commons/src/main/java/org/lfenergy/compas/sct/commons/LnService.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,13 @@ public DoLinkedToDa getDoLinkedToDaCompletedFromDAI(TIED tied, String ldInst, TA
170170
}
171171
if (result.dataAttribute().getFc() == TFCEnum.SG || result.dataAttribute().getFc() == TFCEnum.SE) {
172172
if (hasSettingGroup(tdai)) {
173-
boolean isIedHasConfSG = tied.isSetAccessPoint() &&
173+
boolean isAccessPointConfSG = tied.isSetAccessPoint() &&
174174
tied.getAccessPoint().stream()
175175
.filter(tAccessPoint -> tAccessPoint.getServer() != null
176176
&& tAccessPoint.getServer().getLDevice().stream()
177177
.anyMatch(tlDevice -> tlDevice.getInst().equals(ldInst)))
178-
.anyMatch(tAccessPoint -> tAccessPoint.isSetServices()
179-
&& tAccessPoint.getServices() != null
180-
&& tAccessPoint.getServices().getSettingGroups() != null
181-
&& tAccessPoint.getServices().getSettingGroups().getConfSG() != null);
182-
result.dataAttribute().setValImport((!tdai.isSetValImport() || tdai.isValImport()) && isIedHasConfSG);
178+
.anyMatch(tAccessPoint1 -> hasConfSg(tAccessPoint1.getServices()));
179+
result.dataAttribute().setValImport((!tdai.isSetValImport() || tdai.isValImport()) && (isAccessPointConfSG || hasConfSg(tied.getServices())));
183180
} else {
184181
log.warn("Inconsistency in the SCD file - DAI= {} with fc= {} must have a sGroup attribute", tdai.getName(), result.dataAttribute().getFc());
185182
result.dataAttribute().setValImport(false);
@@ -191,6 +188,12 @@ public DoLinkedToDa getDoLinkedToDaCompletedFromDAI(TIED tied, String ldInst, TA
191188
return result;
192189
}
193190

191+
private static boolean hasConfSg(TServices services) {
192+
return services != null
193+
&& services.getSettingGroups() != null
194+
&& services.getSettingGroups().getConfSG() != null;
195+
}
196+
194197
private boolean hasSettingGroup(TDAI tdai) {
195198
return tdai.isSetVal() && tdai.getVal().stream().anyMatch(tVal -> tVal.isSetSGroup() && tVal.getSGroup() > 0);
196199
}

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

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,6 @@ public Long getConfRev() {
109109
*/
110110
protected abstract void validateSecurityEnabledValue(TServices tServices) throws ScdException;
111111

112-
/**
113-
* Get Control block settings from Service
114-
* @param tServices Service object
115-
* @return ServiceSettingsNoDynEnum enum value
116-
*/
117-
public TServiceSettingsNoDynEnum getControlBlockServiceSetting(TServices tServices){
118-
if(tServices == null) {
119-
return TServiceSettingsNoDynEnum.FIX;
120-
}
121-
return switch (getControlBlockEnum()){
122-
case GSE -> (tServices.getGSESettings() != null) ? tServices.getGSESettings().getCbName() : TServiceSettingsNoDynEnum.FIX;
123-
case SAMPLED_VALUE -> (tServices.getSMVSettings() != null) ? tServices.getSMVSettings().getCbName() : TServiceSettingsNoDynEnum.FIX;
124-
case REPORT -> (tServices.getReportSettings() != null) ? tServices.getReportSettings().getCbName() : TServiceSettingsNoDynEnum.FIX;
125-
default -> TServiceSettingsNoDynEnum.FIX;
126-
};
127-
}
128-
129112
/**
130113
* Add the ControlBlock to an LN or LN0 element
131114
* @param tAnyLN tLN or tLNO element

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

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import org.lfenergy.compas.sct.commons.util.Utils;
1818

1919
import java.util.*;
20+
import java.util.function.Predicate;
21+
import java.util.function.ToLongFunction;
2022
import java.util.stream.Collectors;
2123
import java.util.stream.Stream;
2224

@@ -157,19 +159,17 @@ private Class<? extends TControl> getControlTypeClass(ServicesConfigEnum service
157159
* @return max number authorized by config
158160
*/
159161
private long getMaxInstanceAuthorized(ServicesConfigEnum servicesConfigEnum) {
160-
if (currentElem.getServices() == null)
161-
return MAX_OCCURRENCE_NO_LIMIT_VALUE;
162-
TServices tServices = currentElem.getServices();
163-
164162
return switch (servicesConfigEnum) {
165-
case DATASET -> tServices.isSetConfDataSet() && tServices.getConfDataSet().isSetMax() ?
166-
tServices.getConfDataSet().getMax() : MAX_OCCURRENCE_NO_LIMIT_VALUE;
167-
case FCDA -> tServices.isSetConfDataSet() && tServices.getConfDataSet().isSetMaxAttributes() ?
168-
tServices.getConfDataSet().getMaxAttributes() : MAX_OCCURRENCE_NO_LIMIT_VALUE;
169-
case REPORT -> tServices.isSetConfReportControl() && tServices.getConfReportControl().isSetMax() ?
170-
tServices.getConfReportControl().getMax() : MAX_OCCURRENCE_NO_LIMIT_VALUE;
171-
case GSE -> tServices.isSetGOOSE() && tServices.getGOOSE().isSetMax() ? tServices.getGOOSE().getMax() : MAX_OCCURRENCE_NO_LIMIT_VALUE;
172-
case SMV -> tServices.isSetSMVsc() && tServices.getSMVsc().isSetMax() ? tServices.getSMVsc().getMax() : MAX_OCCURRENCE_NO_LIMIT_VALUE;
163+
case DATASET -> getServicesVal(tServices -> tServices.isSetConfDataSet() && tServices.getConfDataSet().isSetMax(),
164+
tServices -> tServices.getConfDataSet().getMax());
165+
case FCDA -> getServicesVal(tServices -> tServices.isSetConfDataSet() && tServices.getConfDataSet().isSetMaxAttributes(),
166+
tServices -> tServices.getConfDataSet().getMaxAttributes());
167+
case REPORT -> getServicesVal(tServices -> tServices.isSetConfReportControl() && tServices.getConfReportControl().isSetMax(),
168+
tServices -> tServices.getConfReportControl().getMax());
169+
case GSE -> getServicesVal(tServices -> tServices.isSetGOOSE() && tServices.getGOOSE().isSetMax(),
170+
tServices -> tServices.getGOOSE().getMax());
171+
case SMV -> getServicesVal(tServices -> tServices.isSetSMVsc() && tServices.getSMVsc().isSetMax(),
172+
tServices -> tServices.getSMVsc().getMax());
173173
};
174174
}
175175

@@ -180,14 +180,8 @@ private long getMaxInstanceAuthorized(ServicesConfigEnum servicesConfigEnum) {
180180
* @return Optional of encountered error or empty
181181
*/
182182
public Optional<SclReportItem> checkLimitationForBoundIedFcdas(List<TExtRef> tExtRefs) {
183-
long max;
184-
if (currentElem.getServices() == null) {
185-
max = MAX_OCCURRENCE_NO_LIMIT_VALUE;
186-
} else {
187-
TClientServices tClientServices = currentElem.getServices().getClientServices();
188-
max = tClientServices != null && tClientServices.isSetMaxAttributes() ? tClientServices.getMaxAttributes() : MAX_OCCURRENCE_NO_LIMIT_VALUE;
189-
}
190-
if (max == MAX_OCCURRENCE_NO_LIMIT_VALUE) {
183+
long max = getClientServiceVal(TClientServices::isSetMaxAttributes, TClientServices::getMaxAttributes);
184+
if (max == MAX_OCCURRENCE_NO_LIMIT_VALUE){
191185
return Optional.empty();
192186
}
193187
long value = tExtRefs.stream()
@@ -216,6 +210,22 @@ public Optional<SclReportItem> checkLimitationForBoundIedFcdas(List<TExtRef> tEx
216210
"The Client IED %s subscribes to too much FCDA: %d > %d max".formatted(getParentAdapter().getName(), value, max)));
217211
}
218212

213+
private long getClientServiceVal(Predicate<TClientServices> isSet, ToLongFunction<TClientServices> get) {
214+
return getServicesVal(tServices -> tServices.isSetClientServices() && isSet.test(tServices.getClientServices()), tServices -> get.applyAsLong(tServices.getClientServices()));
215+
}
216+
217+
private long getServicesVal(Predicate<TServices> isSet, ToLongFunction<TServices> get) {
218+
if (currentElem.isSetServices() && isSet.test(currentElem.getServices())) {
219+
return get.applyAsLong(currentElem.getServices());
220+
} else {
221+
TIED ied = this.getParentAdapter().getCurrentElem();
222+
if (ied.isSetServices() && isSet.test(ied.getServices())) {
223+
return get.applyAsLong(ied.getServices());
224+
}
225+
}
226+
return AccessPointAdapter.MAX_OCCURRENCE_NO_LIMIT_VALUE;
227+
}
228+
219229
/**
220230
* @param sclReportItems
221231
* @param tExtRefs
@@ -303,15 +313,11 @@ private Optional<SclReportItem> checkLimitationForOneControlType(Set<TExtRef> tE
303313
* @return max number authorized by config
304314
*/
305315
private long getMaxInstanceAuthorizedForBoundIED(ServicesConfigEnum servicesConfigEnum) {
306-
if (currentElem.getServices() == null || currentElem.getServices().getClientServices() == null) {
307-
return AccessPointAdapter.MAX_OCCURRENCE_NO_LIMIT_VALUE;
308-
}
309-
TClientServices tClientServices = currentElem.getServices().getClientServices();
310316
return switch (servicesConfigEnum) {
311-
case FCDA -> tClientServices.isSetMaxAttributes() ? tClientServices.getMaxAttributes() : AccessPointAdapter.MAX_OCCURRENCE_NO_LIMIT_VALUE;
312-
case REPORT -> tClientServices.isSetMaxReports() ? tClientServices.getMaxReports() : AccessPointAdapter.MAX_OCCURRENCE_NO_LIMIT_VALUE;
313-
case GSE -> tClientServices.isSetMaxGOOSE() ? tClientServices.getMaxGOOSE() : AccessPointAdapter.MAX_OCCURRENCE_NO_LIMIT_VALUE;
314-
case SMV -> tClientServices.isSetMaxSMV() ? tClientServices.getMaxSMV() : AccessPointAdapter.MAX_OCCURRENCE_NO_LIMIT_VALUE;
317+
case FCDA -> getClientServiceVal(TClientServices::isSetMaxAttributes, TClientServices::getMaxAttributes);
318+
case REPORT -> getClientServiceVal(TClientServices::isSetMaxReports, TClientServices::getMaxReports);
319+
case GSE -> getClientServiceVal(TClientServices::isSetMaxGOOSE, TClientServices::getMaxGOOSE);
320+
case SMV -> getClientServiceVal(TClientServices::isSetMaxSMV, TClientServices::getMaxSMV);
315321
default -> throw new ScdException("Unsupported value: " + servicesConfigEnum);
316322
};
317323

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
/**
2929
* A representation of the model object
30-
* <em><b>{@link org.lfenergy.compas.scl2007b4.model.TIED IED}</b></em>.
30+
* <em><b>{@link TIED IED}</b></em>.
3131
* <p>
3232
* The following features are supported:
3333
* </p>
@@ -55,8 +55,8 @@
5555
*
5656
* @see LDeviceAdapter
5757
* @see AbstractLNAdapter
58-
* @see org.lfenergy.compas.sct.commons.scl.ied.AbstractDAIAdapter
59-
* @see org.lfenergy.compas.scl2007b4.model.TSettingGroups
58+
* @see AbstractDAIAdapter
59+
* @see TSettingGroups
6060
* @see <a href="https://github.com/com-pas/compas-sct/issues/3" target="_blank">Issue !3 (Add new IEDs)</a>
6161
*/
6262
public class IEDAdapter extends SclElementAdapter<SclRootAdapter, TIED> {
@@ -297,9 +297,14 @@ public boolean isSettingConfig(String ldInst) {
297297
String.format("LD (%s) is unknown in %s", ldInst, getName())
298298
)
299299
);
300+
return hasConfSg(accessPoint.getServices()) || hasConfSg(currentElem.getServices());
301+
}
302+
300303

301-
TServices srv = accessPoint.getServices();
302-
return srv != null && srv.getSettingGroups() != null && srv.getSettingGroups().getConfSG() != null;
304+
private static boolean hasConfSg(TServices services) {
305+
return services != null
306+
&& services.getSettingGroups() != null
307+
&& services.getSettingGroups().getConfSG() != null;
303308
}
304309

305310
/**

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

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.lfenergy.compas.sct.commons.exception.ScdException;
1313
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
1414
import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter;
15+
import org.lfenergy.compas.sct.commons.scl.ied.AccessPointAdapter;
1516
import org.lfenergy.compas.sct.commons.scl.ied.IEDAdapter;
1617
import org.lfenergy.compas.sct.commons.scl.ied.InputsAdapter;
1718
import org.lfenergy.compas.sct.commons.scl.ln.AbstractLNAdapter;
@@ -21,6 +22,8 @@
2122
import org.lfenergy.compas.sct.commons.util.Utils;
2223

2324
import java.util.*;
25+
import java.util.function.Predicate;
26+
import java.util.function.ToLongFunction;
2427
import java.util.stream.Stream;
2528

2629
/**
@@ -346,17 +349,11 @@ public Set<DataAttributeRef> findSourceDA(TExtRef extRef) {
346349
* @return true if parent AccessPoint has the capability, false otherwise
347350
*/
348351
public boolean hasDataSetCreationCapability(ControlBlockEnum controlBlockEnum) {
349-
Objects.requireNonNull(controlBlockEnum);
350-
TAccessPoint accessPoint = getAccessPoint();
351-
if (!accessPoint.isSetServices()) {
352-
return false;
353-
}
354-
TServices services = accessPoint.getServices();
355352
return switch (controlBlockEnum) {
356-
case REPORT -> services.isSetReportSettings() && hasDatSetConfOrDyn(services.getReportSettings());
357-
case GSE -> services.isSetGSESettings() && hasDatSetConfOrDyn(services.getGSESettings());
358-
case SAMPLED_VALUE -> services.isSetSMVSettings() && hasDatSetConfOrDyn(services.getSMVSettings());
359-
case LOG -> services.isSetLogSettings() && hasDatSetConfOrDyn(services.getLogSettings());
353+
case REPORT -> getServicesVal(services ->services.isSetReportSettings() && hasDatSetConfOrDyn(services.getReportSettings()));
354+
case GSE -> getServicesVal(services ->services.isSetGSESettings() && hasDatSetConfOrDyn(services.getGSESettings()));
355+
case SAMPLED_VALUE -> getServicesVal(services ->services.isSetSMVSettings() && hasDatSetConfOrDyn(services.getSMVSettings()));
356+
case LOG -> getServicesVal(services ->services.isSetLogSettings() && hasDatSetConfOrDyn(services.getLogSettings()));
360357
};
361358
}
362359

@@ -372,20 +369,22 @@ private boolean hasDatSetConfOrDyn(TServiceSettings tServiceSettings) {
372369
* @return true if parent AccessPoint has the capability, false otherwise
373370
*/
374371
public boolean hasControlBlockCreationCapability(ControlBlockEnum controlBlockEnum) {
375-
Objects.requireNonNull(controlBlockEnum);
376-
TAccessPoint accessPoint = getAccessPoint();
377-
if (!accessPoint.isSetServices()) {
378-
return false;
379-
}
380-
TServices services = accessPoint.getServices();
381372
return switch (controlBlockEnum) {
382-
case REPORT -> services.isSetReportSettings() && hasCBNameConf(services.getReportSettings());
383-
case GSE -> services.isSetGSESettings() && hasCBNameConf(services.getGSESettings());
384-
case SAMPLED_VALUE -> services.isSetSMVSettings() && hasCBNameConf(services.getSMVSettings());
385-
case LOG -> services.isSetLogSettings() && hasCBNameConf(services.getLogSettings());
373+
case REPORT -> getServicesVal(services -> services.isSetReportSettings() && hasCBNameConf(services.getReportSettings()));
374+
case GSE -> getServicesVal(services ->services.isSetGSESettings() && hasCBNameConf(services.getGSESettings()));
375+
case SAMPLED_VALUE -> getServicesVal(services ->services.isSetSMVSettings() && hasCBNameConf(services.getSMVSettings()));
376+
case LOG -> getServicesVal(services ->services.isSetLogSettings() && hasCBNameConf(services.getLogSettings()));
386377
};
387378
}
388379

380+
private boolean getServicesVal(Predicate<TServices> predicate) {
381+
TAccessPoint accessPoint = getAccessPoint();
382+
TIED ied = this.getParentAdapter().getCurrentElem();
383+
return (accessPoint.isSetServices() && predicate.test(accessPoint.getServices()))
384+
|| (ied.isSetServices() && predicate.test(ied.getServices()));
385+
386+
}
387+
389388
private boolean hasCBNameConf(TServiceSettings tServiceSettings) {
390389
return tServiceSettings.isSetCbName()
391390
&& (TServiceSettingsNoDynEnum.CONF.equals(tServiceSettings.getCbName()));

sct-commons/src/test/java/org/lfenergy/compas/sct/commons/dto/ReportControlBlockTest.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -189,26 +189,6 @@ void testValidateCB() {
189189
assertThatCode(reportControlBlock::validateCB).isInstanceOf(ScdException.class);
190190
}
191191

192-
@Test
193-
@Tag("issue-321")
194-
void testGetControlBlockServiceSetting(){
195-
// Given
196-
ReportControlBlock reportControlBlock = createReportControlBlock();
197-
// When Then
198-
assertThat(reportControlBlock.getControlBlockServiceSetting(null)).isEqualTo(TServiceSettingsNoDynEnum.FIX);
199-
200-
TServices tServices = Mockito.mock(TServices.class);
201-
TReportSettings reportSettings = Mockito.mock(TReportSettings.class);
202-
Mockito.when(tServices.getReportSettings()).thenReturn(reportSettings);
203-
Mockito.when(reportSettings.getCbName()).thenReturn(TServiceSettingsNoDynEnum.CONF);
204-
// When Then
205-
assertThat(reportControlBlock.getControlBlockServiceSetting(tServices)).isEqualTo(TServiceSettingsNoDynEnum.CONF);
206-
207-
Mockito.when(tServices.getReportSettings()).thenReturn(null);
208-
// When Then
209-
assertThat(reportControlBlock.getControlBlockServiceSetting(tServices)).isEqualTo(TServiceSettingsNoDynEnum.FIX);
210-
}
211-
212192
@Test
213193
void validateSecurityEnabledValue_should_do_nothing() {
214194
// Given

sct-commons/src/test/java/org/lfenergy/compas/sct/commons/scl/ied/AccessPointAdapterTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,25 @@ void checkLimitationForBoundIEDControls_should_fail_three_error_messages() {
266266
"The Client IED IED_NAME1 subscribes to too much Report Control Blocks: 1 > 0 max");
267267
}
268268

269+
@Test
270+
void checkLimitationForBoundIEDControls_should_succeed_no_server_access_point_and_server_ied() {
271+
//Given
272+
SCL scd = SclTestMarshaller.getSCLFromResource("limitation_cb_dataset_fcda/scd_check_limitation_bound_ied_controls_fcda.xml");
273+
SclRootAdapter sclRootAdapter = new SclRootAdapter(scd);
274+
IEDAdapter iedAdapter = sclRootAdapter.getIEDAdapterByName("IED_NAME1");
275+
iedAdapter.getCurrentElem().getServices().getClientServices().setMaxAttributes(11L);
276+
iedAdapter.getCurrentElem().getServices().getClientServices().setMaxGOOSE(5L);
277+
iedAdapter.getCurrentElem().getServices().getClientServices().setMaxReports(2L);
278+
iedAdapter.getCurrentElem().getServices().getClientServices().setMaxSMV(2L);
279+
iedAdapter.getCurrentElem().getAccessPoint().forEach(tAccessPoint -> tAccessPoint.setServices(null));
280+
AccessPointAdapter accessPointAdapter = new AccessPointAdapter(iedAdapter, iedAdapter.getCurrentElem().getAccessPoint().getFirst());
281+
List<TExtRef> tExtRefs = accessPointAdapter.getAllCoherentExtRefForAnalyze().tExtRefs();
282+
//When
283+
List<SclReportItem> sclReportItems = accessPointAdapter.checkLimitationForBoundIEDControls(tExtRefs);
284+
//Then
285+
assertThat(sclReportItems).isEmpty();
286+
}
287+
269288
@Test
270289
void checkLimitationForBoundIEDControls_should_succeed_no_error_message() {
271290
//Given

sct-commons/src/test/resources/limitation_cb_dataset_fcda/scd_check_limitation_bound_ied_controls_fcda.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<SCL version="2007" revision="B" release="4" xmlns="http://www.iec.ch/61850/2003/SCL">
77
<Header id="hId" version="2007" revision="B" toolID="COMPAS"/>
88
<IED name="IED_NAME1">
9+
<Services>
10+
<ClientServices maxAttributes="8" maxGOOSE="2" maxReports="0" maxSMV="1" />
11+
</Services>
912
<AccessPoint name="AP_NAME">
1013
<Server>
1114
<Authentication/>

0 commit comments

Comments
 (0)