Skip to content

Commit 28fe773

Browse files
author
Dennis Labordus
committed
Process passed XML file to fix SCL Namespace to become the default + documentation.
Signed-off-by: Dennis Labordus <[email protected]>
1 parent 5b281b4 commit 28fe773

File tree

10 files changed

+260
-15
lines changed

10 files changed

+260
-15
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-FileCopyrightText: 2021 Alliander N.V.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
package org.lfenergy.compas.scl.data.rest;
5+
6+
import org.lfenergy.compas.core.commons.ElementConverter;
7+
import org.lfenergy.compas.scl.data.util.SclDataModelMarshaller;
8+
import org.lfenergy.compas.scl.data.util.SclElementProcessor;
9+
10+
import javax.enterprise.inject.Produces;
11+
12+
/**
13+
* Create Beans from other dependencies that are used in the application.
14+
*/
15+
public class CompasSclDataServiceConfiguration {
16+
@Produces
17+
public ElementConverter createElementConverter() {
18+
return new ElementConverter();
19+
}
20+
21+
@Produces
22+
public SclElementProcessor creatSclElementProcessor() {
23+
return new SclElementProcessor();
24+
}
25+
26+
@Produces
27+
public SclDataModelMarshaller createSclDataModelMarshaller() {
28+
return new SclDataModelMarshaller();
29+
}
30+
}

repository-basex/src/main/java/org/lfenergy/compas/scl/data/repository/CompasSclDataBaseXRepository.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.BASEX_COMMAND_ERROR_CODE;
3131
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.BASEX_QUERY_ERROR_CODE;
3232

33+
/**
34+
* This implementation of the repository will store the SCL XML Files in BaseX, this is a XML Database.
35+
* For more information see https://basex.org/.
36+
* <p>
37+
* For every type of SCL a separate database is created in which the SCL XML Files are stored.
38+
* every entries is stored under &lt;ID&gt;/&lt;Major version&gt;/&lt;Minor version&gt;/&lt;Patch version&gt;/scl.xml.
39+
* This combination is always unique and easy to use.
40+
*/
3341
@ApplicationScoped
3442
public class CompasSclDataBaseXRepository implements CompasSclDataRepository {
3543
private static final Logger LOGGER = LoggerFactory.getLogger(CompasSclDataBaseXRepository.class);
@@ -58,11 +66,12 @@ public class CompasSclDataBaseXRepository implements CompasSclDataRepository {
5866
private final ElementConverter elementConverter;
5967

6068
@Inject
61-
public CompasSclDataBaseXRepository(BaseXClientFactory baseXClientFactory) {
69+
public CompasSclDataBaseXRepository(BaseXClientFactory baseXClientFactory,
70+
ElementConverter elementConverter,
71+
SclDataModelMarshaller sclDataMarshaller) {
6272
this.baseXClientFactory = baseXClientFactory;
63-
64-
this.sclDataMarshaller = new SclDataModelMarshaller();
65-
this.elementConverter = new ElementConverter();
73+
this.sclDataMarshaller = sclDataMarshaller;
74+
this.elementConverter = elementConverter;
6675

6776
// At startup create all needed databases.
6877
Arrays.stream(SclType.values()).forEach(type ->

repository-basex/src/test/java/org/lfenergy/compas/scl/data/repository/CompasSclDataBaseXRepositoryTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.lfenergy.compas.scl.data.model.ChangeSetType;
1515
import org.lfenergy.compas.scl.data.model.SclType;
1616
import org.lfenergy.compas.scl.data.model.Version;
17+
import org.lfenergy.compas.scl.data.util.SclDataModelMarshaller;
1718
import org.lfenergy.compas.scl.data.util.SclElementProcessor;
1819
import org.mockito.junit.jupiter.MockitoExtension;
1920
import org.w3c.dom.Element;
@@ -23,7 +24,8 @@
2324
import static org.junit.jupiter.api.Assertions.*;
2425
import static org.lfenergy.compas.scl.data.Constants.*;
2526
import static org.lfenergy.compas.scl.data.basex.BaseXServerUtil.createClientFactory;
26-
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.*;
27+
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.BASEX_QUERY_ERROR_CODE;
28+
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.HEADER_NOT_FOUND_ERROR_CODE;
2729

2830
@ExtendWith({MockitoExtension.class, BaseXServerJUnitExtension.class})
2931
class CompasSclDataBaseXRepositoryTest {
@@ -35,6 +37,7 @@ class CompasSclDataBaseXRepositoryTest {
3537

3638
private final ElementConverter converter = new ElementConverter();
3739
private final SclElementProcessor processor = new SclElementProcessor();
40+
private final SclDataModelMarshaller marshaller = new SclDataModelMarshaller();
3841

3942
@BeforeAll
4043
static void beforeAll() {
@@ -44,7 +47,7 @@ static void beforeAll() {
4447
@BeforeEach
4548
void beforeEach() throws Exception {
4649
factory.createClient().executeXQuery("db:create('" + TYPE + "')");
47-
repository = new CompasSclDataBaseXRepository(factory);
50+
repository = new CompasSclDataBaseXRepository(factory, converter, marshaller);
4851
}
4952

5053
@Test

repository/src/main/java/org/lfenergy/compas/scl/data/repository/CompasSclDataRepository.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,75 @@
1111
import java.util.List;
1212
import java.util.UUID;
1313

14+
/**
15+
* Repository class that will be used to handle SCL File for a specific type of storage.
16+
* The repository class needs to be able to create and delete entries and find/list entries.
17+
*/
1418
public interface CompasSclDataRepository {
19+
/**
20+
* List the latest version of all SCL Entries for a type of SCL.
21+
*
22+
* @param type The type of SCL to search for.
23+
* @return The list of entries found for the passed type.
24+
*/
1525
List<Item> list(SclType type);
1626

27+
/**
28+
* List all versions for a specific SCL Entry for a type of SCL.
29+
*
30+
* @param type The type of SCL to search for the specific SCL.
31+
* @param id The ID of the SCL to search for.
32+
* @return The list of versions found for that specific sCl Entry.
33+
*/
1734
List<Item> listVersionsByUUID(SclType type, UUID id);
1835

36+
/**
37+
* Return the latest version of a specific SCL Entry.
38+
*
39+
* @param type The type of SCL to search for the specific SCL.
40+
* @param id The ID of the SCL to search for.
41+
* @return The SCL XML File Content that is search for.
42+
*/
1943
Element findByUUID(SclType type, UUID id);
2044

45+
/**
46+
* Return the specific version of a specific SCL Entry.
47+
*
48+
* @param type The type of SCL to search for the specific SCL.
49+
* @param id The ID of the SCL to search for.
50+
* @param version The version of the ScL to search for.
51+
* @return The SCL XML File Content that is search for.
52+
*/
2153
Element findByUUID(SclType type, UUID id, Version version);
2254

55+
/**
56+
* Create a new entry for the passed UUID with the version number passed.
57+
* <p>
58+
* For a complete new entry the service layer will create a new UUID and set the version to 1.0.0.
59+
* When a entry is updated the service layer will increase the version and always create a new entry
60+
* in the repository.
61+
*
62+
* @param type The type of SCL to store it in.
63+
* @param id The ID of the new entry to be created.
64+
* @param scl The SCL XML File content to store.
65+
* @param version The version of the new entry to be created.
66+
*/
2367
void create(SclType type, UUID id, Element scl, Version version);
2468

69+
/**
70+
* Delete all versions for a specific SCL File using it's ID.
71+
*
72+
* @param type The type of SCL where to find the SCL File
73+
* @param id The ID of the SCL File to delete.
74+
*/
2575
void delete(SclType type, UUID id);
2676

77+
/**
78+
* Delete passed versions for a specific SCL File using it's ID.
79+
*
80+
* @param type The type of SCL where to find the SCL File
81+
* @param id The ID of the SCL File to delete.
82+
* @param version The version of that SCL File to delete.
83+
*/
2784
void delete(SclType type, UUID id, Version version);
2885
}

repository/src/main/java/org/lfenergy/compas/scl/data/util/SclElementProcessor.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,42 @@
66
import org.lfenergy.compas.scl.data.exception.CompasSclDataServiceException;
77
import org.w3c.dom.Element;
88
import org.w3c.dom.Node;
9+
import org.w3c.dom.NodeList;
910

10-
import java.util.ArrayList;
11-
import java.util.List;
12-
import java.util.Optional;
11+
import java.util.*;
1312

1413
import static org.lfenergy.compas.scl.data.Constants.*;
1514
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.HEADER_NOT_FOUND_ERROR_CODE;
15+
import static org.w3c.dom.Node.ELEMENT_NODE;
1616

1717
public class SclElementProcessor {
18+
public void fixDefaultPrefix(Node root) {
19+
var oldNamespacePrefixes = new HashSet<String>();
20+
var nodes = new Stack<Node>();
21+
nodes.push(root);
22+
23+
while (!nodes.isEmpty()) {
24+
var node = nodes.pop();
25+
if (node.getNodeType() == ELEMENT_NODE && SCL_NS_URI.equals(node.getNamespaceURI())
26+
&& node.getPrefix() != null && !node.getPrefix().isBlank()) {
27+
oldNamespacePrefixes.add(node.getPrefix());
28+
node.setPrefix("");
29+
}
30+
31+
// For child nodes of this node
32+
NodeList childNodes = node.getChildNodes();
33+
if (childNodes != null) {
34+
for (int i = 0, count = childNodes.getLength(); i < count; ++i) {
35+
nodes.push(childNodes.item(i));
36+
}
37+
}
38+
}
39+
40+
oldNamespacePrefixes.forEach(
41+
prefix -> root.getAttributes().removeNamedItem("xmlns:" + prefix)
42+
);
43+
}
44+
1845
public Optional<Element> getSclHeader(Element scl) {
1946
return getChildNodesByName(scl, SCL_HEADER_ELEMENT_NAME).stream()
2047
.findFirst();

repository/src/test/java/org/lfenergy/compas/scl/data/util/SclElementProcessorTest.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,47 @@
1111
import static org.junit.jupiter.api.Assertions.*;
1212
import static org.lfenergy.compas.scl.data.Constants.*;
1313
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.HEADER_NOT_FOUND_ERROR_CODE;
14-
import static org.lfenergy.compas.scl.data.exception.CompasSclDataServiceErrorCode.UNMARSHAL_ERROR_CODE;
1514

1615
class SclElementProcessorTest {
1716
private SclElementProcessor processor = new SclElementProcessor();
1817
private ElementConverter converter = new ElementConverter();
1918

19+
@Test
20+
void fixDefaultPrefix_WhenCalledWithDifferentSclPrefix_ThenPrefixIsSetToDefaultAndAttributeRemoved() {
21+
var scl = readSCL("scl_with_prefix.scd");
22+
23+
assertTrue(scl.hasAttribute("xmlns:scl"));
24+
assertEquals("scl", scl.getPrefix());
25+
var header = processor.getSclHeader(scl);
26+
assertEquals("scl", header.get().getPrefix());
27+
28+
/// Fix the namespace prefix
29+
processor.fixDefaultPrefix(scl);
30+
31+
assertFalse(scl.hasAttribute("xmlns:scl"));
32+
assertNull(scl.getPrefix());
33+
header = processor.getSclHeader(scl);
34+
assertNull(header.get().getPrefix());
35+
}
36+
37+
@Test
38+
void fixDefaultPrefix_WhenCalledWithDefaultSclPrefix_ThenNothingIsDone() {
39+
var scl = readSCL("scl_with_default_prefix.scd");
40+
41+
assertFalse(scl.hasAttribute("xmlns:scl"));
42+
assertNull(scl.getPrefix());
43+
var header = processor.getSclHeader(scl);
44+
assertNull(header.get().getPrefix());
45+
46+
/// Fix the namespace prefix
47+
processor.fixDefaultPrefix(scl);
48+
49+
assertFalse(scl.hasAttribute("xmlns:scl"));
50+
assertNull(scl.getPrefix());
51+
header = processor.getSclHeader(scl);
52+
assertNull(header.get().getPrefix());
53+
}
54+
2055
@Test
2156
void getSclHeader_WhenCalledWithSclContainingAHeader_ThenHeaderReturned() {
2257
var scl = readSCL("scl_with_header.scd");
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!-- SPDX-FileCopyrightText: 2021 Alliander N.V. -->
2+
<!-- -->
3+
<!-- SPDX-License-Identifier: Apache-2.0 -->
4+
<SCL xmlns="http://www.iec.ch/61850/2003/SCL" xmlns:compas="https://www.lfenergy.org/compas/v1" version="2007" revision="B" release="4">
5+
<Header id="370e5d89-df3a-4d9b-a651-3dc5cb28bee1" version="1.0.0"/>
6+
</SCL>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!-- SPDX-FileCopyrightText: 2021 Alliander N.V. -->
2+
<!-- -->
3+
<!-- SPDX-License-Identifier: Apache-2.0 -->
4+
<scl:SCL xmlns:scl="http://www.iec.ch/61850/2003/SCL" xmlns:compas="https://www.lfenergy.org/compas/v1" version="2007" revision="B" release="4">
5+
<scl:Header id="370e5d89-df3a-4d9b-a651-3dc5cb28bee1" version="1.0.0"/>
6+
</scl:SCL>

0 commit comments

Comments
 (0)