Skip to content

Commit ee69c20

Browse files
authored
Merge pull request #540 from com-pas/feat/539-rsr-1021-add-bayservice-and-lnodeservice-to-browse-substation-section
feat(#539): RSR-1021 Add BayService and LNodeService to browse the substation section
2 parents 8b181db + 39472fd commit ee69c20

File tree

5 files changed

+335
-3
lines changed

5 files changed

+335
-3
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-FileCopyrightText: 2023 2024 RTE FRANCE
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.sct.commons;
6+
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.lfenergy.compas.scl2007b4.model.SCL;
9+
import org.lfenergy.compas.scl2007b4.model.TBay;
10+
import org.lfenergy.compas.scl2007b4.model.TSubstation;
11+
12+
import java.util.Optional;
13+
import java.util.function.Predicate;
14+
import java.util.stream.Stream;
15+
16+
@Slf4j
17+
public class BayService {
18+
19+
public Stream<TBay> getBays(SCL scl) {
20+
return scl.getSubstation().stream().flatMap(this::getBays);
21+
}
22+
23+
public Stream<TBay> getBays(TSubstation tSubstation) {
24+
return tSubstation.getVoltageLevel().stream()
25+
.flatMap(tVoltageLevel -> tVoltageLevel.getBay().stream());
26+
}
27+
28+
public Stream<TBay> getFilteredBays(TSubstation tSubstation, Predicate<TBay> bayPredicate) {
29+
return getBays(tSubstation).filter(bayPredicate);
30+
}
31+
32+
public Optional<TBay> findBay(TSubstation tSubstation, Predicate<TBay> bayPredicate) {
33+
return getFilteredBays(tSubstation, bayPredicate).findFirst();
34+
}
35+
36+
public Optional<TBay> findBay(TSubstation tSubstation, String bayName) {
37+
return findBay(tSubstation, bay -> bay.getName().equals(bayName));
38+
}
39+
40+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-FileCopyrightText: 2023 2024 RTE FRANCE
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.sct.commons;
6+
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.apache.commons.lang3.StringUtils;
9+
import org.lfenergy.compas.scl2007b4.model.*;
10+
11+
import java.util.Optional;
12+
import java.util.function.Predicate;
13+
import java.util.stream.Stream;
14+
15+
@Slf4j
16+
public class LNodeService {
17+
18+
public Stream<TLNode> getLNodes(TBay tBay) {
19+
return tBay.getFunction().stream()
20+
.flatMap(tFunction -> tFunction.getLNode().stream());
21+
}
22+
23+
public Stream<TLNode> getFilteredLNodes(TBay tBay, Predicate<TLNode> tlNodePredicate) {
24+
return getLNodes(tBay).filter(tlNodePredicate);
25+
}
26+
27+
public Optional<TLNode> findLNode(TBay tBay, Predicate<TLNode> tlNodePredicate) {
28+
return getFilteredLNodes(tBay, tlNodePredicate).findFirst();
29+
}
30+
31+
public boolean matchesLnode(TLNode tlNode, String iedName, String ldInst, TAnyLN tAnyLN) {
32+
return switch (tAnyLN) {
33+
case TLN ln -> matchesLnode(tlNode, iedName, ldInst, ln.getLnClass().isEmpty() ? "" : ln.getLnClass().getFirst(), ln.getInst(), ln.getPrefix());
34+
case LN0 ln0 -> matchesLnode(tlNode, iedName, ldInst, TLLN0Enum.LLN_0.value(), ln0.getInst(), "");
35+
default -> throw new IllegalStateException("Unexpected value: " + tAnyLN);
36+
};
37+
}
38+
39+
public boolean matchesLnode(TLNode tlNode, String iedName, String ldInst, String lnClass, String lnInst, String lnPrefix) {
40+
return tlNode.getIedName().equals(iedName)
41+
&& tlNode.getLdInst().equals(ldInst)
42+
&& tlNode.getLnClass().contains(lnClass)
43+
&& StringUtils.trimToEmpty(lnInst).equals(StringUtils.trimToEmpty(tlNode.getLnInst()))
44+
&& StringUtils.trimToEmpty(lnPrefix).equals(StringUtils.trimToEmpty(tlNode.getPrefix()));
45+
}
46+
47+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
public class LnService implements LnEditor {
2727

2828
private static final DoLinkedToDaFilter DAI_FILTER_MOD_STVAL = DoLinkedToDaFilter.from(MOD_DO_NAME, STVAL_DA_NAME);
29-
private static final String LNODE_STATUS_PRIVATE_TYPE = "COMPAS-LNodeStatus";
29+
public static final String LNODE_STATUS_PRIVATE_TYPE = "COMPAS-LNodeStatus";
3030

3131
public Stream<TAnyLN> getAnylns(TLDevice tlDevice) {
3232
return Stream.concat(Stream.of(tlDevice.getLN0()), tlDevice.getLN().stream());
@@ -58,10 +58,10 @@ public Optional<TLN> findLn(TLDevice tlDevice, Predicate<TLN> lnPredicate) {
5858

5959
public boolean matchesLn(TAnyLN tAnyLN, String lnClass, String lnInst, String lnPrefix) {
6060
return switch (tAnyLN) {
61-
case TLN ln -> lnClass.equals(ln.getLnClass().getFirst())
61+
case TLN ln -> ln.getLnClass().contains(lnClass)
6262
&& StringUtils.trimToEmpty(lnInst).equals(StringUtils.trimToEmpty(ln.getInst()))
6363
&& (StringUtils.trimToEmpty(lnPrefix).equals(StringUtils.trimToEmpty(ln.getPrefix())));
64-
case LN0 ignored -> lnClass.equals(TLLN0Enum.LLN_0.value());
64+
case LN0 ignored -> TLLN0Enum.LLN_0.value().equals(lnClass);
6565
default -> throw new IllegalStateException("Unexpected value: " + tAnyLN);
6666
};
6767
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// SPDX-FileCopyrightText: 2025 RTE FRANCE
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.sct.commons;
6+
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.Test;
9+
import org.lfenergy.compas.scl2007b4.model.SCL;
10+
import org.lfenergy.compas.scl2007b4.model.TBay;
11+
import org.lfenergy.compas.scl2007b4.model.TSubstation;
12+
import org.lfenergy.compas.scl2007b4.model.TVoltageLevel;
13+
14+
import java.util.Optional;
15+
import java.util.stream.Stream;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
19+
class BayServiceTest {
20+
21+
private BayService bayService;
22+
23+
@BeforeEach
24+
void setUp() {
25+
bayService = new BayService();
26+
27+
}
28+
29+
@Test
30+
void getBays_on_Scl_should_return_bays() {
31+
// Given
32+
SCL scl = new SCL();
33+
TSubstation tSubstation = createSubstation();
34+
scl.getSubstation().add(tSubstation);
35+
36+
// When
37+
Stream<TBay> bays = bayService.getBays(scl);
38+
39+
// Then
40+
assertThat(bays)
41+
.extracting(TBay::getName)
42+
.containsExactlyInAnyOrder("BayA", "BayB", "BayC");
43+
}
44+
45+
@Test
46+
void getBays_on_Substation_should_return_bays() {
47+
// Given
48+
TSubstation tSubstation = createSubstation();
49+
50+
// When
51+
Stream<TBay> bays = bayService.getBays(tSubstation);
52+
53+
// Then
54+
assertThat(bays)
55+
.extracting(TBay::getName)
56+
.containsExactlyInAnyOrder("BayA", "BayB", "BayC");
57+
}
58+
59+
@Test
60+
void getFilteredBays_should_succeed() {
61+
// Given
62+
TSubstation tSubstation = createSubstation();
63+
// When
64+
Stream<TBay> result = bayService.getFilteredBays(tSubstation, tBay -> tBay.getName().equals("BayA") || tBay.getName().equals("BayC"));
65+
// Then
66+
assertThat(result)
67+
.extracting(TBay::getName)
68+
.containsExactlyInAnyOrder("BayA", "BayC");
69+
}
70+
71+
@Test
72+
void findBay_by_predicate_should_succeed() {
73+
// Given
74+
TSubstation tSubstation = createSubstation();
75+
// When
76+
Optional<TBay> result = bayService.findBay(tSubstation, tBay -> tBay.getName().equals("BayA"));
77+
// Then
78+
assertThat(result)
79+
.map(TBay::getName)
80+
.hasValue("BayA");
81+
}
82+
83+
@Test
84+
void findBay_by_name_should_succeed() {
85+
// Given
86+
TSubstation tSubstation = createSubstation();
87+
// When
88+
Optional<TBay> result = bayService.findBay(tSubstation, "BayA");
89+
// Then
90+
assertThat(result)
91+
.map(TBay::getName)
92+
.hasValue("BayA");
93+
}
94+
95+
@Test
96+
void findBay_should_succeed() {
97+
// Given
98+
TSubstation tSubstation = createSubstation();
99+
// When
100+
Optional<TBay> result = bayService.findBay(tSubstation, "BayA");
101+
// Then
102+
assertThat(result)
103+
.map(TBay::getName)
104+
.hasValue("BayA");
105+
}
106+
107+
private static TSubstation createSubstation() {
108+
TSubstation tSubstation = new TSubstation();
109+
TVoltageLevel tVoltageLevel1 = new TVoltageLevel();
110+
tSubstation.getVoltageLevel().add(tVoltageLevel1);
111+
tVoltageLevel1.getBay().add(createBay("BayA"));
112+
tVoltageLevel1.getBay().add(createBay("BayB"));
113+
TVoltageLevel tVoltagelevel2 = new TVoltageLevel();
114+
tSubstation.getVoltageLevel().add(tVoltagelevel2);
115+
tVoltagelevel2.getBay().add(createBay("BayC"));
116+
return tSubstation;
117+
}
118+
119+
private static TBay createBay(String name) {
120+
TBay bay = new TBay();
121+
bay.setName(name);
122+
return bay;
123+
}
124+
125+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// SPDX-FileCopyrightText: 2025 RTE FRANCE
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.sct.commons;
6+
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.Test;
9+
import org.lfenergy.compas.scl2007b4.model.*;
10+
11+
import java.util.List;
12+
import java.util.Optional;
13+
import java.util.stream.Stream;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
17+
class LNodeServiceTest {
18+
19+
private LNodeService lNodeService;
20+
21+
@BeforeEach
22+
void setUp() {
23+
lNodeService = new LNodeService();
24+
}
25+
26+
@Test
27+
void getLNodes_should_return_all_lnodes() {
28+
//Given
29+
TBay tBay = createBay();
30+
//When
31+
Stream<TLNode> lNodes = lNodeService.getLNodes(tBay);
32+
//Then
33+
assertThat(lNodes)
34+
.extracting(TLNode::getLdInst)
35+
.containsExactlyInAnyOrder("LDInst1", "LDInst2", "LDInst3");
36+
}
37+
38+
@Test
39+
void getFilteredLNodes_should_return_lnodes() {
40+
//Given
41+
TBay tBay = createBay();
42+
//When
43+
Stream<TLNode> lNodes = lNodeService.getFilteredLNodes(tBay, tLNode -> tLNode.getLdInst().equals("LDInst2") || tLNode.getLdInst().equals("LDInst3"));
44+
//Then
45+
assertThat(lNodes)
46+
.extracting(TLNode::getLdInst)
47+
.containsExactlyInAnyOrder("LDInst2", "LDInst3");
48+
}
49+
50+
@Test
51+
void findLNode_should_return_lnode() {
52+
//Given
53+
TBay tBay = createBay();
54+
//When
55+
Optional<TLNode> lNodes = lNodeService.findLNode(tBay, tLNode -> tLNode.getLdInst().equals("LDInst2"));
56+
//Then
57+
assertThat(lNodes)
58+
.map(TLNode::getLdInst)
59+
.hasValue("LDInst2");
60+
}
61+
62+
@Test
63+
void matchesLnode_should_match_lnode() {
64+
//Given
65+
TLNode lNode = createLNode(1);
66+
//When
67+
boolean matches = lNodeService.matchesLnode(lNode, "IED1", "LDInst1", "LNClass1", "LNInst1", "Prefix1");
68+
//Then
69+
assertThat(matches).isTrue();
70+
}
71+
72+
@Test
73+
void matchesLnode_on_LN_should_match_lnode() {
74+
//Given
75+
TLNode lNode = createLNode(1);
76+
TLN tln = new TLN();
77+
tln.getLnClass().add("LNClass1");
78+
tln.setInst("LNInst1");
79+
tln.setPrefix("Prefix1");
80+
//When
81+
boolean matches = lNodeService.matchesLnode(lNode, "IED1", "LDInst1", tln);
82+
//Then
83+
assertThat(matches).isTrue();
84+
}
85+
86+
@Test
87+
void matchesLnode_on_LN0_should_match_lnode() {
88+
//Given
89+
TLNode lNode = new TLNode();
90+
lNode.setIedName("IED1");
91+
lNode.setLdInst("LDInst1");
92+
lNode.getLnClass().add("LLN0");
93+
LN0 ln0 = new LN0();
94+
//When
95+
boolean matches = lNodeService.matchesLnode(lNode, "IED1", "LDInst1", ln0);
96+
//Then
97+
assertThat(matches).isTrue();
98+
}
99+
100+
private static TBay createBay() {
101+
TBay tBay = new TBay();
102+
tBay.setName("BayA");
103+
TFunction tFunction1 = new TFunction();
104+
tFunction1.getLNode().addAll(List.of(createLNode(1), createLNode(2)));
105+
TFunction tFunction2 = new TFunction();
106+
tFunction2.getLNode().add(createLNode(3));
107+
tBay.getFunction().addAll(List.of(tFunction1, tFunction2));
108+
return tBay;
109+
}
110+
111+
private static TLNode createLNode(int index) {
112+
TLNode tLNode = new TLNode();
113+
tLNode.setIedName("IED" + index);
114+
tLNode.setLdInst("LDInst" + index);
115+
tLNode.getLnClass().add("LNClass" + index);
116+
tLNode.setLnInst("LNInst" + index);
117+
tLNode.setPrefix("Prefix" + index);
118+
return tLNode;
119+
}
120+
}

0 commit comments

Comments
 (0)