StringWriter.java
package net.hostsharing.hsadminng.rbac.generator;
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;
static VarDef with(final String var, final String name) {
return new VarDef(var, name, false);
}
static VarDef withQuoted(final String var, final String name) {
return new VarDef(var, name, true);
}
void writeLn(final String text) {
string.append( indented(text));
writeLn();
}
String writeLn(final String text, final VarDef... varDefs) {
final var insertText = indented(new VarReplacer(varDefs).apply(text));
string.append(insertText);
writeLn();
return insertText;
}
void writeLn() {
string.append( "\n");
}
void indent() {
++indentLevel;
}
void unindent() {
--indentLevel;
}
void indent(int levels) {
indentLevel += levels;
}
void unindent(int levels) {
indentLevel -= levels;
}
void indented(final Runnable indented) {
indent();
indented.run();
unindent();
}
void indented(int levels, final Runnable indented) {
indent(levels);
indented.run();
unindent(levels);
}
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 ensureSingleEmptyLine() {
chopEmptyLines();
writeLn();
}
@Override
public String toString() {
return string.toString();
}
public static String indented(final int indentLevel, final String text) {
final var indentation = StringUtils.repeat(" ", indentLevel);
final var indented = stream(text.split("\n"))
.map(line -> line.trim().isBlank() ? "" : indentation + line)
.collect(joining("\n"));
return indented;
}
private String indented(final String text) {
if ( indentLevel == 0) {
return text;
}
return indented(indentLevel, text);
}
record VarDef(String name, String value, boolean quoted) {}
private static final class VarReplacer {
private final VarDef[] varDefs;
private String text;
private VarReplacer(VarDef[] varDefs) {
this.varDefs = varDefs;
}
String apply(final String textToAppend) {
text = textToAppend;
stream(varDefs).forEach(varDef -> {
replacePlaceholder(varDef.name(),
varDef.quoted()
? varDef.value() != null
? "$" + varDef.name() + "$\n" + varDef.value() + "\n$" + varDef.name() + "$"
: "null"
: varDef.value());
});
return text;
}
private void replacePlaceholder(final String name, final String value) {
// TODO.impl: I actually want a case-independent search+replace but ...
// for which the substitution String can contain sequences of "${...}" to be replaced by further varDefs.
text = text.replace("${" + name+ "}", value);
text = text.replace("${" + name.toUpperCase() + "}", value);
text = text.replace("${" + name.toLowerCase() + "}", value);
}
}
}