diff --git a/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/CassandraAppStorage.java b/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/CassandraAppStorage.java index 19572ad9..48773f1e 100644 --- a/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/CassandraAppStorage.java +++ b/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/CassandraAppStorage.java @@ -52,6 +52,8 @@ public class CassandraAppStorage extends AbstractAppStorage { public static final String ORPHAN_DATA = "ORPHAN_DATA"; + public static final String DISPLAY_TREE = "DISPLAY_TREE"; + private final String fileSystemName; private final Supplier contextSupplier; @@ -1488,7 +1490,7 @@ public void close() { @Override public List getSupportedFileSystemChecks() { return ImmutableList.of(FileSystemCheckOptions.EXPIRED_INCONSISTENT_NODES, - REF_NOT_FOUND, ORPHAN_NODE, ORPHAN_DATA); + REF_NOT_FOUND, ORPHAN_NODE, ORPHAN_DATA, DISPLAY_TREE); } @Override @@ -1510,6 +1512,9 @@ public List checkFileSystem(FileSystemCheckOptions options case ORPHAN_DATA: checkOrphanData(results, options); break; + case DISPLAY_TREE: + displayTree(results); + break; default: LOGGER.warn("Check {} not supported in {}", type, getClass()); } @@ -1518,6 +1523,11 @@ public List checkFileSystem(FileSystemCheckOptions options return results; } + private void displayTree(List results) { + ResultSet allTables = getSession().execute(select(ID, NAME, PSEUDO_CLASS, CHILD_ID, PARENT_ID).from(CHILDREN_BY_NAME_AND_CLASS)); + results.add(new DisplayTreeIssueBuilder(allTables).build()); + } + private void checkOrphanData(List results, FileSystemCheckOptions options) { Set existingNodeIds = new HashSet<>(); Set orphanDataIds = new HashSet<>(); diff --git a/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/DisplayTreeIssueBuilder.java b/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/DisplayTreeIssueBuilder.java new file mode 100644 index 00000000..e7e091d3 --- /dev/null +++ b/afs-cassandra/src/main/java/com/powsybl/afs/cassandra/DisplayTreeIssueBuilder.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package com.powsybl.afs.cassandra; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.powsybl.afs.storage.check.FileSystemCheckIssue; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author Yichen TANG + */ +class DisplayTreeIssueBuilder { + + private final TreeNode root = new TreeNode("display tree"); + private final Map nodes = new HashMap<>(); + private final Map infos = new HashMap<>(); + + DisplayTreeIssueBuilder(ResultSet resultSet) { + for (Row row : resultSet) { + RowBean rowBean = new RowBean(row.getUUID(0).toString(), + row.getString(1), + row.getString(2), + row.getUUID(3) == null ? null : row.getUUID(3).toString()); + cacheNodeInfo(rowBean); + nodes.computeIfAbsent(rowBean.id, TreeNode::new); + if (rowBean.cId != null) { + nodes.computeIfAbsent(rowBean.cId, TreeNode::new); + nodes.get(rowBean.id).children.add(rowBean.cId); + } + if (row.getUUID(4) == null) { + root.children.add(rowBean.id); + } + } + } + + private void cacheNodeInfo(RowBean bean) { + if (!infos.containsKey(bean.id)) { + infos.put(bean.id, new NodeInfo(bean.name, bean.pseudoClass)); + } + } + + static class NodeInfo { + + private final String name; + private final String pseudoClass; + + NodeInfo(String name, String pseudoClass) { + this.name = name; + this.pseudoClass = pseudoClass; + } + + @Override + public String toString() { + return name + "(" + pseudoClass + ")"; + } + } + + static class RowBean { + + private final String id; + private final String name; + private final String pseudoClass; + private final String cId; + + RowBean(String id, String name, String pseudoClass, String cId) { + this.id = id; + this.name = name; + this.pseudoClass = pseudoClass; + this.cId = cId; + } + } + + static class TreeNode { + String id; + String name; + Set children = new HashSet<>(); + + TreeNode(String id) { + this.id = id; + } + + TreeNode(String id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return id + "_" + name; + } + } + + FileSystemCheckIssue build() { + StringBuilder sb = new StringBuilder(); + printNode(sb, root, 0); + return new FileSystemCheckIssue().setDescription(sb.toString()); + } + + void printNode(StringBuilder sb, TreeNode node, int level) { + for (int i = 0; i < level - 1; i++) { + sb.append(" "); + } + if (level != 0) { + sb.append(infos.get(node.id)) + .append(" ") + .append(node.id) + .append("\n"); + } + int nextLevel = level + 1; + node.children.forEach(e -> printNode(sb, nodes.get(e), nextLevel)); + } +} diff --git a/afs-cassandra/src/test/java/com/powsybl/afs/cassandra/CassandraAppStorageTest.java b/afs-cassandra/src/test/java/com/powsybl/afs/cassandra/CassandraAppStorageTest.java index 677e983c..b9185c05 100644 --- a/afs-cassandra/src/test/java/com/powsybl/afs/cassandra/CassandraAppStorageTest.java +++ b/afs-cassandra/src/test/java/com/powsybl/afs/cassandra/CassandraAppStorageTest.java @@ -216,7 +216,8 @@ void testSupportedChecks() { .containsExactlyInAnyOrder(CassandraAppStorage.REF_NOT_FOUND, FileSystemCheckOptions.EXPIRED_INCONSISTENT_NODES, CassandraAppStorage.ORPHAN_NODE, - CassandraAppStorage.ORPHAN_DATA + CassandraAppStorage.ORPHAN_DATA, + CassandraAppStorage.DISPLAY_TREE ); }