From b4d6930fbeb9ac669f70426929fed233048961e3 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Sun, 25 Feb 2024 11:58:45 +0100 Subject: [PATCH] introduce StringWriter and generate properly indented Flowchart --- .../rbacdef/RbacViewMermaidFlowchart.java | 71 ++++++++++--------- .../hsadminng/rbac/rbacdef/StringWriter.java | 71 +++++++++++++++++++ .../test/cust/TestCustomerEntityTest.java | 2 +- 3 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/StringWriter.java diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewMermaidFlowchart.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewMermaidFlowchart.java index 9f34673f..f7286316 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewMermaidFlowchart.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacViewMermaidFlowchart.java @@ -1,7 +1,5 @@ package net.hostsharing.hsadminng.rbac.rbacdef; -import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; -import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import org.apache.commons.lang3.StringUtils; @@ -16,11 +14,11 @@ public class RbacViewMermaidFlowchart { public static final String HOSTSHARING_ORANGE = "#dd4901"; public static final String HOSTSHARING_LIGHTBLUE = "#99bcdb"; private final RbacView rbacDef; - private final StringBuilder flowchart = new StringBuilder(); + private final StringWriter flowchart = new StringWriter(); public RbacViewMermaidFlowchart(final RbacView rbacDef) { this.rbacDef = rbacDef; - flowchart.append(""" + flowchart.writeLn(""" %%{init:{'flowchart':{'htmlLabels':false}}}%% flowchart TB """); @@ -36,54 +34,63 @@ public class RbacViewMermaidFlowchart { private void renderEntitySubgraph(final RbacView.EntityAlias entity) { final var color = rbacDef.isMainEntityAlias(entity) ? HOSTSHARING_ORANGE : HOSTSHARING_LIGHTBLUE; - flowchart.append(""" + flowchart.writeLn(""" subgraph %{aliasName}["`**%{aliasName}**`"] direction TB style %{aliasName} fill:%{color},stroke:darkblue,stroke-width:8px - """ .replace("%{aliasName}", entity.aliasName()) .replace("%{color}", color )); - rbacDef.getEntityAliases().values().stream() - .filter(e -> e.aliasName().startsWith(entity.aliasName() + ".")) - .forEach(this::renderEntitySubgraph); + flowchart.indented( () -> { + rbacDef.getEntityAliases().values().stream() + .filter(e -> e.aliasName().startsWith(entity.aliasName() + ".")) + .forEach(this::renderEntitySubgraph); - wrapOutputInSubgraph(entity.aliasName() + ":roles", color, - rbacDef.getRoleDefs().stream() - .filter(r -> r.getEntityAlias() == entity) - .map(r -> " " + roleDef(r)) - .collect(joining("\n"))); - - wrapOutputInSubgraph(entity.aliasName() + ":permissions", color, - rbacDef.getPermDefs().stream() - .filter(p -> p.getEntityAlias() == entity) - .map(p -> " " + permDef(p) ) + wrapOutputInSubgraph(entity.aliasName() + ":roles", color, + rbacDef.getRoleDefs().stream() + .filter(r -> r.getEntityAlias() == entity) + .map(r -> " " + roleDef(r)) .collect(joining("\n"))); - if (rbacDef.isMainEntityAlias(entity) && rbacDef.getEntityAliasProxy() != null ) { - renderEntitySubgraph(rbacDef.getEntityAliasProxy()); - } + wrapOutputInSubgraph(entity.aliasName() + ":permissions", color, + rbacDef.getPermDefs().stream() + .filter(p -> p.getEntityAlias() == entity) + .map(p -> " " + permDef(p) ) + .collect(joining("\n"))); - flowchart.append("end\n\n"); + if (rbacDef.isMainEntityAlias(entity) && rbacDef.getEntityAliasProxy() != null ) { + renderEntitySubgraph(rbacDef.getEntityAliasProxy()); + } + + }); + flowchart.chopEmptyLines(); + flowchart.writeLn("end"); + flowchart.writeLn(); } private void wrapOutputInSubgraph(final String name, final String color, final String content) { if (!StringUtils.isEmpty(content)) { - flowchart.append("subgraph " + name + "[ ]\n"); - flowchart.append("style %{aliasName} fill: %{color}\n\n" - .replace("%{aliasName}", name) - .replace("%{color}", color)); - flowchart.append(content); - flowchart.append("\nend\n\n"); + flowchart.emptyLine(); + flowchart.writeLn("subgraph " + name + "[ ]\n"); + flowchart.indented(() -> { + flowchart.writeLn("style %{aliasName} fill: %{color}" + .replace("%{aliasName}", name) + .replace("%{color}", color)); + flowchart.writeLn(); + flowchart.writeLn(content); + }); + flowchart.chopEmptyLines(); + flowchart.writeLn("end"); + flowchart.writeLn(); } } private void renderGrants() { rbacDef.getGrantDefs() .forEach(g -> { - flowchart.append(grantDef(g) + "\n" ); + flowchart.writeLn(grantDef(g) + "\n"); }); } @@ -141,8 +148,8 @@ public class RbacViewMermaidFlowchart { } public static void main(String[] args) throws IOException { - new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.rbac()).generateToMarkdownFile(); +// new RbacViewMermaidFlowchart(HsOfficeBankAccountEntity.rbac()).generateToMarkdownFile(); new RbacViewMermaidFlowchart(HsOfficeRelationshipEntity.rbac()).generateToMarkdownFile(); - new RbacViewMermaidFlowchart(HsOfficeDebitorEntity.rbac()).generateToMarkdownFile(); +// new RbacViewMermaidFlowchart(HsOfficeDebitorEntity.rbac()).generateToMarkdownFile(); } } diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/StringWriter.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/StringWriter.java new file mode 100644 index 00000000..9b0bfc7a --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/StringWriter.java @@ -0,0 +1,71 @@ +package net.hostsharing.hsadminng.rbac.rbacdef; + +import org.apache.commons.lang3.StringUtils; + +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.joining; + +public class StringWriter { + + private final StringBuilder string = new StringBuilder(); + private int indentLevel = 0; + + void writeLn(final String text) { + string.append( indented(text)); + writeLn(); + } + + void writeLn() { + string.append( "\n"); + } + + private String indented(final String text) { + if ( indentLevel == 0) { + return text.trim(); + } + final var indentation = StringUtils.repeat(" ", indentLevel); + final var indented = stream(text.split("\n")) + .map(line -> line.trim().isBlank() ? "" : indentation + line.trim()) + .collect(joining("\n")); + return indented; + } + + void indent() { + ++indentLevel; + } + + void unindent() { + --indentLevel; + } + + void indented(final Runnable indented) { + indent(); + indented.run(); + unindent(); + } + + boolean chopTail(final String tail) { + if (string.toString().endsWith(tail)) { + string.setLength(string.length() - tail.length()); + return true; + } + return false; + } + + void chopEmptyLines() { + while (string.toString().endsWith("\n\n")) { + string.setLength(string.length() - 1); + }; + } + + void emptyLine() { + if (!string.toString().endsWith("\n\n")) { + writeLn(); + } + } + + @Override + public String toString() { + return string.toString(); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityTest.java b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityTest.java index c7f9800a..9bdbafc6 100644 --- a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityTest.java +++ b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntityTest.java @@ -27,7 +27,7 @@ class TestCustomerEntityTest { end subgraph contact:permissions[ ] - style contact:permissions fill: #dd4901 + style contact:permissions fill: #dd4901 perm:contact:*{{contact:*}} perm:contact:add-package{{contact:add-package}}