Skip to content

Commit 1f60bd2

Browse files
author
Dennis Labordus
committed
Refactor cleanup and support multiple substations.
Signed-off-by: Dennis Labordus <[email protected]>
1 parent 1c432d6 commit 1f60bd2

File tree

11 files changed

+285
-67
lines changed

11 files changed

+285
-67
lines changed

app/src/main/java/org/lfenergy/compas/scl/auto/alignment/rest/v1/SclAutoAlignmentResource.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.lfenergy.compas.scl.auto.alignment.rest.UserInfoProperties;
99
import org.lfenergy.compas.scl.auto.alignment.rest.v1.model.SclAutoAlignRequest;
1010
import org.lfenergy.compas.scl.auto.alignment.rest.v1.model.SclAutoAlignResponse;
11+
import org.lfenergy.compas.scl.auto.alignment.rest.v1.model.SclAutoAlignSVGRequest;
1112
import org.lfenergy.compas.scl.auto.alignment.service.SclAutoAlignmentService;
1213
import org.slf4j.Logger;
1314
import org.slf4j.LoggerFactory;
@@ -48,15 +49,15 @@ public SclAutoAlignResponse updateSCL(@Valid SclAutoAlignRequest request) {
4849
LOGGER.trace("Username used for Who {}", who);
4950

5051
var response = new SclAutoAlignResponse();
51-
response.setSclData(sclAutoAlignmentService.updateSCL(request.getSclData(), request.getSubstationName(), who));
52+
response.setSclData(sclAutoAlignmentService.updateSCL(request.getSclData(), request.getSubstationNames(), who));
5253
return response;
5354
}
5455

5556
@POST
5657
@Consumes(MediaType.APPLICATION_XML)
5758
@Produces(MediaType.APPLICATION_SVG_XML)
5859
@Path("/svg")
59-
public String getSVG(@Valid SclAutoAlignRequest request) {
60+
public String getSVG(@Valid SclAutoAlignSVGRequest request) {
6061
return sclAutoAlignmentService.getSVG(request.getSclData(), request.getSubstationName());
6162
}
6263
}

app/src/main/java/org/lfenergy/compas/scl/auto/alignment/rest/v1/model/SclAutoAlignRequest.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
import org.eclipse.microprofile.openapi.annotations.media.Schema;
88

99
import javax.validation.constraints.NotBlank;
10+
import javax.validation.constraints.NotEmpty;
1011
import javax.xml.bind.annotation.XmlAccessType;
1112
import javax.xml.bind.annotation.XmlAccessorType;
1213
import javax.xml.bind.annotation.XmlElement;
1314
import javax.xml.bind.annotation.XmlRootElement;
15+
import java.util.ArrayList;
16+
import java.util.List;
1417

1518
import static org.lfenergy.compas.scl.auto.alignment.SclAutoAlignmentConstants.SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI;
1619

@@ -19,21 +22,21 @@
1922
@XmlAccessorType(XmlAccessType.FIELD)
2023
public class SclAutoAlignRequest {
2124
@Schema(description = "")
22-
@NotBlank
25+
@NotEmpty
2326
@XmlElement(name = "SubstationName", namespace = SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI)
24-
protected String substationName;
27+
protected List<String> substationNames = new ArrayList<>();
2528

2629
@Schema(description = "")
2730
@NotBlank
2831
@XmlElement(name = "SclData", namespace = SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI)
2932
protected String sclData;
3033

31-
public String getSubstationName() {
32-
return substationName;
34+
public List<String> getSubstationNames() {
35+
return substationNames;
3336
}
3437

35-
public void setSubstationName(String substationName) {
36-
this.substationName = substationName;
38+
public void setSubstationNames(List<String> substationNames) {
39+
this.substationNames = substationNames;
3740
}
3841

3942
public String getSclData() {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// SPDX-FileCopyrightText: 2021 Alliander N.V.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.lfenergy.compas.scl.auto.alignment.rest.v1.model;
6+
7+
import org.eclipse.microprofile.openapi.annotations.media.Schema;
8+
9+
import javax.validation.constraints.NotBlank;
10+
import javax.xml.bind.annotation.XmlAccessType;
11+
import javax.xml.bind.annotation.XmlAccessorType;
12+
import javax.xml.bind.annotation.XmlElement;
13+
import javax.xml.bind.annotation.XmlRootElement;
14+
15+
import static org.lfenergy.compas.scl.auto.alignment.SclAutoAlignmentConstants.SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI;
16+
17+
@Schema(description = "")
18+
@XmlRootElement(name = "SclAutoAlignRequest", namespace = SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI)
19+
@XmlAccessorType(XmlAccessType.FIELD)
20+
public class SclAutoAlignSVGRequest {
21+
@Schema(description = "")
22+
@NotBlank
23+
@XmlElement(name = "SubstationName", namespace = SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI)
24+
protected String substationName;
25+
26+
@Schema(description = "")
27+
@NotBlank
28+
@XmlElement(name = "SclData", namespace = SCL_AUTO_ALIGNMENT_SERVICE_V1_NS_URI)
29+
protected String sclData;
30+
31+
public String getSubstationName() {
32+
return substationName;
33+
}
34+
35+
public void setSubstationName(String substationName) {
36+
this.substationName = substationName;
37+
}
38+
39+
public String getSclData() {
40+
return sclData;
41+
}
42+
43+
public void setSclData(String sclData) {
44+
this.sclData = sclData;
45+
}
46+
}

app/src/test/java/org/lfenergy/compas/scl/auto/alignment/rest/v1/SclAutoAlignmentResourceTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
import io.restassured.http.ContentType;
1313
import org.junit.jupiter.api.Test;
1414
import org.lfenergy.compas.scl.auto.alignment.rest.v1.model.SclAutoAlignRequest;
15+
import org.lfenergy.compas.scl.auto.alignment.rest.v1.model.SclAutoAlignSVGRequest;
1516
import org.lfenergy.compas.scl.auto.alignment.service.SclAutoAlignmentService;
1617

1718
import java.io.IOException;
1819
import java.nio.file.Files;
1920
import java.nio.file.Paths;
21+
import java.util.List;
2022

2123
import static io.restassured.RestAssured.given;
2224
import static io.restassured.path.xml.config.XmlPathConfig.xmlPathConfig;
@@ -44,12 +46,13 @@ class SclAutoAlignmentResourceTest {
4446

4547
@Test
4648
void updateSCL_WhenCalled_ThenExpectedResponseIsRetrieved() throws IOException {
49+
var names = List.of(SUBSTATION_NAME);
4750
var request = new SclAutoAlignRequest();
48-
request.setSubstationName(SUBSTATION_NAME);
51+
request.setSubstationNames(names);
4952
request.setSclData(readFile());
5053

5154
var expectedResult = "SCL XML";
52-
when(sclAutoAlignmentService.updateSCL(any(), eq(SUBSTATION_NAME), eq(USERNAME))).thenReturn(expectedResult);
55+
when(sclAutoAlignmentService.updateSCL(any(), eq(names), eq(USERNAME))).thenReturn(expectedResult);
5356

5457
var response = given()
5558
.contentType(ContentType.XML)
@@ -66,12 +69,12 @@ void updateSCL_WhenCalled_ThenExpectedResponseIsRetrieved() throws IOException {
6669
var scl = xmlPath.getString("saa:SclAutoAlignmentResponse.SclData");
6770
assertNotNull(scl);
6871
assertEquals(expectedResult, scl);
69-
verify(sclAutoAlignmentService, times(1)).updateSCL(any(), eq(SUBSTATION_NAME), eq(USERNAME));
72+
verify(sclAutoAlignmentService, times(1)).updateSCL(any(), eq(names), eq(USERNAME));
7073
}
7174

7275
@Test
7376
void getSVG_WhenCalled_ThenExpectedResponseIsRetrieved() throws IOException {
74-
var request = new SclAutoAlignRequest();
77+
var request = new SclAutoAlignSVGRequest();
7578
request.setSubstationName(SUBSTATION_NAME);
7679
request.setSclData(readFile());
7780

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// SPDX-FileCopyrightText: 2021 Alliander N.V.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
package org.lfenergy.compas.scl.auto.alignment.rest.v1.model;
5+
6+
class SclAutoAlignSVGRequestTest extends AbstractPojoTester {
7+
@Override
8+
protected Class<?> getClassToBeTested() {
9+
return SclAutoAlignSVGRequest.class;
10+
}
11+
}

service/src/main/java/org/lfenergy/compas/scl/auto/alignment/common/CommonUtil.java

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,55 @@
33
// SPDX-License-Identifier: Apache-2.0
44
package org.lfenergy.compas.scl.auto.alignment.common;
55

6-
import java.util.regex.Pattern;
6+
import org.w3c.dom.Attr;
7+
import org.w3c.dom.Element;
8+
9+
import java.util.stream.Collectors;
10+
import java.util.stream.IntStream;
711

812
import static org.lfenergy.compas.scl.auto.alignment.SclAutoAlignmentConstants.SCLXY_NS_URI;
913

14+
/**
15+
* Some common methods used in the Auto Alignment Service.
16+
*/
1017
public class CommonUtil {
1118
CommonUtil() {
1219
throw new UnsupportedOperationException("CommonUtil class");
1320
}
1421

15-
public static String cleanSXYDeclarationAndAttributes(String data) {
16-
// Find Prefix of Namespace.
17-
var pattern = Pattern.compile("xmlns:([A-Za-z0-9]*)=\\\"" + SCLXY_NS_URI + "\\\"");
18-
var matcher = pattern.matcher(data);
22+
/**
23+
* Remove attributes from the element related to the namespace SCLXY_NS_URI
24+
* {@link org.lfenergy.compas.scl.auto.alignment.SclAutoAlignmentConstants}.
25+
* It will also remove the attributes from all child elements.
26+
*
27+
* @param element The Element to start from removing the attributes.
28+
*/
29+
public static void cleanSXYDeclarationAndAttributes(Element element) {
30+
// First collect the attributes to be removed.
31+
var attributes = element.getAttributes();
32+
var attributesToRemove = IntStream.range(0, attributes.getLength())
33+
.mapToObj(attributes::item)
34+
.filter(Attr.class::isInstance)
35+
.map(Attr.class::cast)
36+
.filter(attr -> SCLXY_NS_URI.equals(attr.getNamespaceURI()))
37+
.collect(Collectors.toList());
38+
// Remove the attribute from the element.
39+
attributesToRemove.forEach(element::removeAttributeNode);
40+
41+
// Check if there is a declaration that can be removed
42+
IntStream.range(0, attributes.getLength())
43+
.mapToObj(attributes::item)
44+
.filter(Attr.class::isInstance)
45+
.map(Attr.class::cast)
46+
.filter(attr -> SCLXY_NS_URI.equals(attr.getValue()))
47+
.forEach(element::removeAttributeNode);
1948

20-
if (matcher.find()) {
21-
var prefix = matcher.group(1);
22-
var replacementPattern = "xmlns:[A-Za-z0-9]*=\\\"" + SCLXY_NS_URI + "\\\"" + // Remove the namespace declaration.
23-
"|" + // Combine the two regex patterns.
24-
"[ ]?" + prefix + ":[A-Za-z]*=\\\"[A-Za-z0-9]*\\\""; // Remove the attributes using that namespace.
25-
return data.replaceAll(replacementPattern, "");
26-
}
27-
return data;
49+
// Next cleanup all the child elements in the same way.
50+
var nodes = element.getChildNodes();
51+
IntStream.range(0, nodes.getLength())
52+
.mapToObj(nodes::item)
53+
.filter(Element.class::isInstance)
54+
.map(Element.class::cast)
55+
.forEach(CommonUtil::cleanSXYDeclarationAndAttributes);
2856
}
2957
}

service/src/main/java/org/lfenergy/compas/scl/auto/alignment/service/SclAutoAlignmentEnricher.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import java.util.concurrent.atomic.AtomicLong;
1313

14+
import static org.lfenergy.compas.scl.auto.alignment.common.CommonUtil.cleanSXYDeclarationAndAttributes;
15+
1416
public class SclAutoAlignmentEnricher {
1517
private final GenericSCL scl;
1618
private final String jsonGraphInfo;
@@ -25,6 +27,10 @@ public void enrich() {
2527
var substationName = jsonSubstation.get("substationId").getAsString();
2628
var sclSubstation = scl.getSubstation(substationName);
2729
sclSubstation.ifPresent(substation -> {
30+
// First we will remove all old information from this Substation.
31+
cleanSXYDeclarationAndAttributes(substation.getElement());
32+
33+
// Next process the VoltageLevels.
2834
if (jsonSubstation.has("voltageLevels")) {
2935
jsonSubstation.getAsJsonArray("voltageLevels")
3036
.forEach(jsonVoltageLevel -> enrichVoltageLevel(substation, jsonVoltageLevel.getAsJsonObject()));

service/src/main/java/org/lfenergy/compas/scl/auto/alignment/service/SclAutoAlignmentService.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
import java.io.ByteArrayInputStream;
2323
import java.io.StringWriter;
2424
import java.nio.charset.StandardCharsets;
25+
import java.util.List;
2526
import java.util.Optional;
2627

2728
import static org.lfenergy.compas.scl.auto.alignment.SclAutoAlignmentConstants.SCL_ELEMENT_NAME;
2829
import static org.lfenergy.compas.scl.auto.alignment.SclAutoAlignmentConstants.SCL_NS_URI;
29-
import static org.lfenergy.compas.scl.auto.alignment.common.CommonUtil.cleanSXYDeclarationAndAttributes;
3030
import static org.lfenergy.compas.scl.auto.alignment.exception.SclAutoAlignmentErrorCode.NO_SCL_ELEMENT_FOUND_ERROR_CODE;
3131
import static org.lfenergy.compas.scl.auto.alignment.exception.SclAutoAlignmentErrorCode.SUBSTATION_NOT_FOUND_ERROR_CODE;
3232

@@ -39,15 +39,18 @@ public SclAutoAlignmentService(ElementConverter converter) {
3939
this.converter = converter;
4040
}
4141

42-
public String updateSCL(String sclData, String substationName, String who) {
42+
public String updateSCL(String sclData, List<String> substationNames, String who) {
4343
var scl = readSCL(sclData);
44-
var substationBuilder = createSubstationBuilder(scl.getSubstation(substationName), substationName);
4544

46-
// Create the JSON With all X/Y Coordinate information.
47-
var jsonGraphInfo = createJson(substationBuilder);
48-
// Use that JSON to enrich the passed SCL XML with X/Y Coordinates.
49-
var enricher = new SclAutoAlignmentEnricher(scl, jsonGraphInfo);
50-
enricher.enrich();
45+
substationNames.forEach(substationName -> {
46+
var substationBuilder = createSubstationBuilder(scl.getSubstation(substationName), substationName);
47+
48+
// Create the JSON With all X/Y Coordinate information.
49+
var jsonGraphInfo = createJson(substationBuilder);
50+
// Use that JSON to enrich the passed SCL XML with X/Y Coordinates.
51+
var enricher = new SclAutoAlignmentEnricher(scl, jsonGraphInfo);
52+
enricher.enrich();
53+
});
5154

5255
// Add an extra History Element to show there was a change.
5356
scl.getOrCreateHeader().addHistoryItem(who, "Add or replaced the X/Y Coordinates in the SCL File.");
@@ -63,12 +66,9 @@ public String getSVG(String sclData, String substationName) {
6366
}
6467

6568
GenericSCL readSCL(String sclData) {
66-
// First we will cleanup existing X/Y Coordinates from the SCL XML.
67-
var cleanSclData = cleanSXYDeclarationAndAttributes(sclData);
68-
6969
// Next convert the String to W3C Document/Element
7070
var sclElement = converter.convertToElement(new BufferedInputStream(
71-
new ByteArrayInputStream(cleanSclData.getBytes(StandardCharsets.UTF_8))), SCL_ELEMENT_NAME, SCL_NS_URI);
71+
new ByteArrayInputStream(sclData.getBytes(StandardCharsets.UTF_8))), SCL_ELEMENT_NAME, SCL_NS_URI);
7272
if (sclElement == null) {
7373
throw new SclAutoAlignmentException(NO_SCL_ELEMENT_FOUND_ERROR_CODE, "No valid SCL found in the passed SCL Data.");
7474
}

0 commit comments

Comments
 (0)