diff --git a/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentExpression.java b/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentExpression.java index 4010b9c2b..cfd35d96e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentExpression.java +++ b/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentExpression.java @@ -138,7 +138,7 @@ public class AssignmentExpression { private PermissionToken(String permission) { this.permission = permission; - this.node = LegacyNodeFactory.fromSerializedNode(permission, true); + this.node = LegacyNodeFactory.fromLegacyString(permission, true); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentRule.java b/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentRule.java index 1bcf2d203..e71e3e0b9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentRule.java +++ b/common/src/main/java/me/lucko/luckperms/common/assignments/AssignmentRule.java @@ -51,8 +51,8 @@ public class AssignmentRule { this.hasTrueExpression = AssignmentExpression.compile(hasTrueExpression); this.hasFalseExpression = AssignmentExpression.compile(hasFalseExpression); this.lacksExpression = AssignmentExpression.compile(lacksExpression); - this.toGive = toGive.stream().map(s -> LegacyNodeFactory.fromSerializedNode(s, true)).collect(ImmutableCollectors.toList());; - this.toTake = toTake.stream().map(s -> LegacyNodeFactory.fromSerializedNode(s, true)).collect(ImmutableCollectors.toList()); + this.toGive = toGive.stream().map(s -> LegacyNodeFactory.fromLegacyString(s, true)).collect(ImmutableCollectors.toList());; + this.toTake = toTake.stream().map(s -> LegacyNodeFactory.fromLegacyString(s, true)).collect(ImmutableCollectors.toList()); this.setPrimaryGroup = setPrimaryGroup; } diff --git a/common/src/main/java/me/lucko/luckperms/common/constants/DataConstraints.java b/common/src/main/java/me/lucko/luckperms/common/constants/DataConstraints.java index 354aede00..63d5fc6d0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/constants/DataConstraints.java +++ b/common/src/main/java/me/lucko/luckperms/common/constants/DataConstraints.java @@ -35,8 +35,6 @@ import java.util.regex.Pattern; @UtilityClass public class DataConstraints { - public static final Pattern RESERVED_CHARACTERS_PATTERN = Pattern.compile("[\\/\\$\\.]"); - public static final int MAX_PERMISSION_LENGTH = 200; public static final int MAX_TRACK_NAME_LENGTH = 36; @@ -85,10 +83,6 @@ public class DataConstraints { return false; } - if (RESERVED_CHARACTERS_PATTERN.matcher(s).find()) { - return false; - } - return true; }; @@ -97,10 +91,6 @@ public class DataConstraints { return false; } - if (RESERVED_CHARACTERS_PATTERN.matcher(s).find()) { - return false; - } - return true; }; @@ -113,10 +103,6 @@ public class DataConstraints { return false; } - if (RESERVED_CHARACTERS_PATTERN.matcher(s).find()) { - return false; - } - return true; }; @@ -125,10 +111,6 @@ public class DataConstraints { return false; } - if (RESERVED_CHARACTERS_PATTERN.matcher(s).find()) { - return false; - } - return true; }; @@ -143,10 +125,6 @@ public class DataConstraints { return false; } - if (RESERVED_CHARACTERS_PATTERN.matcher(s).find()) { - return false; - } - return true; }; @@ -159,10 +137,6 @@ public class DataConstraints { return false; } - if (RESERVED_CHARACTERS_PATTERN.matcher(s).find()) { - return false; - } - return true; }; diff --git a/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java b/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java index c21be700a..3b67270a6 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java @@ -54,17 +54,6 @@ public final class ImmutableNode implements Node { */ private static final int NODE_SEPARATOR_CHAR = Character.getNumericValue('.'); - /** - * The characters which are delimited when serializing a permission string - */ - private static final String[] PERMISSION_DELIMITERS = new String[]{"/", "-", "$", "(", ")", "=", ","}; - - /** - * The characters which are delimited when serializing a server or world string - */ - private static final String[] SERVER_WORLD_DELIMITERS = new String[]{"/", "-"}; - - /* * NODE STATE * @@ -146,12 +135,12 @@ public final class ImmutableNode implements Node { world = standardizeServerWorld(world); // define core attributes - this.permission = NodeFactory.unescapeDelimiters(permission, PERMISSION_DELIMITERS).intern(); + this.permission = LegacyNodeFactory.unescapeDelimiters(permission, LegacyNodeFactory.PERMISSION_DELIMITERS).intern(); this.value = value; this.override = override; this.expireAt = expireAt; - this.server = internString(NodeFactory.unescapeDelimiters(server, SERVER_WORLD_DELIMITERS)); - this.world = internString(NodeFactory.unescapeDelimiters(world, SERVER_WORLD_DELIMITERS)); + this.server = internString(LegacyNodeFactory.unescapeDelimiters(server, LegacyNodeFactory.SERVER_WORLD_DELIMITERS)); + this.world = internString(LegacyNodeFactory.unescapeDelimiters(world, LegacyNodeFactory.SERVER_WORLD_DELIMITERS)); this.contexts = contexts == null ? ContextSet.empty() : contexts.makeImmutable(); // define cached state diff --git a/common/src/main/java/me/lucko/luckperms/common/node/LegacyNodeFactory.java b/common/src/main/java/me/lucko/luckperms/common/node/LegacyNodeFactory.java index 9fc506beb..7b17aa835 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/LegacyNodeFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/LegacyNodeFactory.java @@ -40,6 +40,26 @@ import java.util.regex.Pattern; @UtilityClass public class LegacyNodeFactory { + /** + * The characters which are delimited when serializing a permission string + */ + static final String[] PERMISSION_DELIMITERS = new String[]{"/", "-", "$", "(", ")", "=", ","}; + + /** + * The characters which are delimited when serializing a server or world string + */ + static final String[] SERVER_WORLD_DELIMITERS = new String[]{"/", "-"}; + + /** + * The characters which are delimited when serializing a context set + */ + static final String[] CONTEXT_DELIMITERS = new String[]{"=", "(", ")", ","}; + + /** + * The characters which are delimited when serializing meta/prefix/suffix strings + */ + private static final String[] GENERIC_DELIMITERS = new String[]{".", "/", "-", "$"}; + // legacy node format delimiters private static final Pattern LEGACY_SERVER_DELIM = PatternCache.compileDelimitedMatcher("/", "\\"); private static final Splitter LEGACY_SERVER_SPLITTER = Splitter.on(LEGACY_SERVER_DELIM).limit(2); @@ -47,8 +67,44 @@ public class LegacyNodeFactory { private static final Splitter LEGACY_WORLD_SPLITTER = Splitter.on(LEGACY_WORLD_DELIM).limit(2); private static final Pattern LEGACY_EXPIRY_DELIM = PatternCache.compileDelimitedMatcher("$", "\\"); private static final Splitter LEGACY_EXPIRY_SPLITTER = Splitter.on(LEGACY_EXPIRY_DELIM).limit(2); + private static final Pattern LEGACY_CONTEXT_DELIM = PatternCache.compileDelimitedMatcher(")", "\\"); + private static final Splitter CONTEXT_SPLITTER = Splitter.on(LEGACY_CONTEXT_DELIM).limit(2); + private static final Pattern LEGACY_CONTEXT_PAIR_DELIM = PatternCache.compileDelimitedMatcher(",", "\\"); + private static final Pattern LEGACY_CONTEXT_PAIR_PART_DELIM = PatternCache.compileDelimitedMatcher("=", "\\"); + private static final Splitter.MapSplitter LEGACY_CONTEXT_PART_SPLITTER = Splitter.on(LEGACY_CONTEXT_PAIR_DELIM) + .withKeyValueSeparator(Splitter.on(LEGACY_CONTEXT_PAIR_PART_DELIM)); - public static Node fromSerializedNode(String s, boolean b) { + public static String toSerializedNode(Node node) { + StringBuilder builder = new StringBuilder(); + + if (node.getServer().orElse(null) != null) { + builder.append(escapeDelimiters(node.getServer().orElse(null), SERVER_WORLD_DELIMITERS)); + if (node.getWorld().orElse(null) != null) { + builder.append("-").append(escapeDelimiters(node.getWorld().orElse(null), SERVER_WORLD_DELIMITERS)); + } + builder.append("/"); + } else { + if (node.getWorld().orElse(null) != null) { + builder.append("global-").append(escapeDelimiters(node.getWorld().orElse(null), SERVER_WORLD_DELIMITERS)).append("/"); + } + } + + if (!node.getContexts().isEmpty()) { + builder.append("("); + for (Map.Entry entry : node.getContexts().toSet()) { + builder.append(escapeDelimiters(entry.getKey(), CONTEXT_DELIMITERS)) + .append("=").append(escapeDelimiters(entry.getValue(), CONTEXT_DELIMITERS)).append(","); + } + builder.deleteCharAt(builder.length() - 1); + builder.append(")"); + } + + builder.append(escapeDelimiters(node.getPermission(), PERMISSION_DELIMITERS)); + if (node.isTemporary()) builder.append("$").append(node.getExpiryUnixTime()); + return builder.toString(); + } + + public static Node fromLegacyString(String s, boolean b) { if (b) { return builderFromLegacyString(s, true).build(); } else { @@ -115,6 +171,51 @@ public class LegacyNodeFactory { } } + static String escapeCharacters(String s) { + if (s == null) { + throw new NullPointerException(); + } + + return escapeDelimiters(s, GENERIC_DELIMITERS); + } + + static String unescapeCharacters(String s) { + if (s == null) { + throw new NullPointerException(); + } + + // super old hack - this format is no longer used for escaping, + // but we'll keep supporting it when unescaping + s = s.replace("{SEP}", "."); + s = s.replace("{FSEP}", "/"); + s = s.replace("{DSEP}", "$"); + s = unescapeDelimiters(s, GENERIC_DELIMITERS); + + return s; + } + + private static String escapeDelimiters(String s, String... delimiters) { + if (s == null) { + return null; + } + + for (String d : delimiters) { + s = s.replace(d, "\\" + d); + } + return s; + } + + static String unescapeDelimiters(String s, String... delimiters) { + if (s == null) { + return null; + } + + for (String d : delimiters) { + s = s.replace("\\" + d, d); + } + return s; + } + private static final class LegacyNodeBuilder extends NodeBuilder { private static final Pattern NODE_CONTEXTS_PATTERN = Pattern.compile("\\(.+\\).*"); @@ -122,14 +223,17 @@ public class LegacyNodeFactory { if (!NODE_CONTEXTS_PATTERN.matcher(permission).matches()) { this.permission = permission; } else { - List contextParts = Splitter.on(PatternCache.compileDelimitedMatcher(")", "\\")).limit(2).splitToList(permission.substring(1)); + List contextParts = CONTEXT_SPLITTER.splitToList(permission.substring(1)); // 0 = context, 1 = node this.permission = contextParts.get(1); try { - Map map = Splitter.on(PatternCache.compileDelimitedMatcher(",", "\\")).withKeyValueSeparator(Splitter.on(PatternCache.compileDelimitedMatcher("=", "\\"))).split(contextParts.get(0)); + Map map = LEGACY_CONTEXT_PART_SPLITTER.split(contextParts.get(0)); for (Map.Entry e : map.entrySet()) { - this.withExtraContext(NodeFactory.unescapeDelimiters(e.getKey(), "=", "(", ")", ","), NodeFactory.unescapeDelimiters(e.getValue(), "=", "(", ")", ",")); + this.withExtraContext( + unescapeDelimiters(e.getKey(), CONTEXT_DELIMITERS), + unescapeDelimiters(e.getValue(), CONTEXT_DELIMITERS) + ); } } catch (IllegalArgumentException e) { diff --git a/common/src/main/java/me/lucko/luckperms/common/node/NodeFactory.java b/common/src/main/java/me/lucko/luckperms/common/node/NodeFactory.java index ba505616d..c879ffc06 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/NodeFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/NodeFactory.java @@ -40,14 +40,13 @@ import java.util.Iterator; import java.util.Map; /** - * Utility class to make Node(Builder) instances from serialised strings or existing Nodes + * Utility class to make Node(Builder) instances from strings or existing Nodes */ @UtilityClass public class NodeFactory { // used to split prefix/suffix/meta nodes private static final Splitter META_SPLITTER = Splitter.on(PatternCache.compileDelimitedMatcher(".", "\\")).limit(2); - private static final String[] DELIMS = new String[]{".", "/", "-", "$"}; public static Node.Builder newBuilder(String s) { return new NodeBuilder(s); @@ -65,7 +64,7 @@ public class NodeFactory { return makeSuffixNode(100, value); } - return new NodeBuilder("meta." + escapeCharacters(key) + "." + escapeCharacters(value)); + return new NodeBuilder("meta." + LegacyNodeFactory.escapeCharacters(key) + "." + LegacyNodeFactory.escapeCharacters(value)); } public static Node.Builder makeChatMetaNode(ChatMetaType type, int priority, String s) { @@ -73,11 +72,11 @@ public class NodeFactory { } public static Node.Builder makePrefixNode(int priority, String prefix) { - return new NodeBuilder("prefix." + priority + "." + escapeCharacters(prefix)); + return new NodeBuilder("prefix." + priority + "." + LegacyNodeFactory.escapeCharacters(prefix)); } public static Node.Builder makeSuffixNode(int priority, String suffix) { - return new NodeBuilder("suffix." + priority + "." + escapeCharacters(suffix)); + return new NodeBuilder("suffix." + priority + "." + LegacyNodeFactory.escapeCharacters(suffix)); } public static String nodeAsCommand(Node node, String id, boolean group, boolean set) { @@ -173,49 +172,6 @@ public class NodeFactory { return sb; } - public static String escapeCharacters(String s) { - if (s == null) { - throw new NullPointerException(); - } - - return escapeDelimiters(s, DELIMS); - } - - public static String unescapeCharacters(String s) { - if (s == null) { - throw new NullPointerException(); - } - - s = s.replace("{SEP}", "."); - s = s.replace("{FSEP}", "/"); - s = s.replace("{DSEP}", "$"); - s = unescapeDelimiters(s, DELIMS); - - return s; - } - - public static String escapeDelimiters(String s, String... delims) { - if (s == null) { - return null; - } - - for (String delim : delims) { - s = s.replace(delim, "\\" + delim); - } - return s; - } - - public static String unescapeDelimiters(String s, String... delims) { - if (s == null) { - return null; - } - - for (String delim : delims) { - s = s.replace("\\" + delim, delim); - } - return s; - } - public static String parseGroupNode(String s) { String lower = s.toLowerCase(); if (!lower.startsWith("group.")) { @@ -237,7 +193,7 @@ public class NodeFactory { if (!metaParts.hasNext()) return null; String value = metaParts.next(); - return Maps.immutableEntry(unescapeCharacters(key).intern(), unescapeCharacters(value).intern()); + return Maps.immutableEntry(LegacyNodeFactory.unescapeCharacters(key).intern(), LegacyNodeFactory.unescapeCharacters(value).intern()); } private static Map.Entry parseChatMetaNode(String type, String s) { @@ -255,7 +211,7 @@ public class NodeFactory { try { int p = Integer.parseInt(priority); - String v = unescapeCharacters(value).intern(); + String v = LegacyNodeFactory.unescapeCharacters(value).intern(); return Maps.immutableEntry(p, v); } catch (NumberFormatException e) { return null; diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyJsonMigration.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyJsonMigration.java index 8b7cbc14c..5f7f6059a 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyJsonMigration.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyJsonMigration.java @@ -112,7 +112,7 @@ public class LegacyJsonMigration implements Runnable { Set nodes = perms.entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .map(NodeModel::fromNode) .collect(Collectors.toCollection(LinkedHashSet::new)); @@ -162,7 +162,7 @@ public class LegacyJsonMigration implements Runnable { } Set nodes = perms.entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .map(NodeModel::fromNode) .collect(Collectors.toCollection(LinkedHashSet::new)); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacySqlMigration.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacySqlMigration.java index 9494be36b..0d7679f91 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacySqlMigration.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacySqlMigration.java @@ -154,7 +154,7 @@ public class LegacySqlMigration implements Runnable { } Set nodes = convertedPerms.entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .map(NodeModel::fromNode) .collect(Collectors.toSet()); @@ -233,7 +233,7 @@ public class LegacySqlMigration implements Runnable { } Set nodes = convertedPerms.entrySet().stream() - .map(ent -> LegacyNodeFactory.fromSerializedNode(ent.getKey(), ent.getValue())) + .map(ent -> LegacyNodeFactory.fromLegacyString(ent.getKey(), ent.getValue())) .map(NodeModel::fromNode) .collect(Collectors.toSet()); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyYamlMigration.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyYamlMigration.java index 8575fe90d..4cc713a5d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyYamlMigration.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/legacy/LegacyYamlMigration.java @@ -114,7 +114,7 @@ public class LegacyYamlMigration implements Runnable { perms.putAll((Map) data.get("perms")); Set nodes = perms.entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .map(NodeModel::fromNode) .collect(Collectors.toCollection(LinkedHashSet::new)); @@ -161,7 +161,7 @@ public class LegacyYamlMigration implements Runnable { perms.putAll((Map) data.get("perms")); Set nodes = perms.entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .map(NodeModel::fromNode) .collect(Collectors.toCollection(LinkedHashSet::new)); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java index 9ea7247e0..f9b137d2f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/mongodb/MongoDao.java @@ -49,7 +49,6 @@ import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.node.LegacyNodeFactory; -import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeHeldPermission; import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; @@ -232,7 +231,7 @@ public class MongoDao extends AbstractDao { Set nodes = new HashSet<>(); for (Map.Entry e : perms.entrySet()) { - Node node = LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue()); + Node node = LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue()); nodes.add(NodeModel.fromNode(node)); } @@ -266,7 +265,7 @@ public class MongoDao extends AbstractDao { Set nodes = new HashSet<>(); for (Map.Entry e : perms.entrySet()) { - Node node = LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue()); + Node node = LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue()); nodes.add(NodeModel.fromNode(node)); } @@ -306,7 +305,7 @@ public class MongoDao extends AbstractDao { // User exists, let's load. Document d = cursor.next(); user.setEnduringNodes(revert((Map) d.get("perms")).entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .collect(Collectors.toSet()) ); user.getPrimaryGroup().setStoredValue(d.getString("primaryGroup")); @@ -394,7 +393,7 @@ public class MongoDao extends AbstractDao { Map perms = revert((Map) d.get("perms")); for (Map.Entry e : perms.entrySet()) { - Node node = LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue()); + Node node = LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue()); if (!node.getPermission().equalsIgnoreCase(permission)) { continue; } @@ -422,7 +421,7 @@ public class MongoDao extends AbstractDao { // Group exists, let's load. Document d = cursor.next(); group.setEnduringNodes(revert((Map) d.get("perms")).entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .collect(Collectors.toSet()) ); } else { @@ -452,7 +451,7 @@ public class MongoDao extends AbstractDao { Document d = cursor.next(); group.setEnduringNodes(revert((Map) d.get("perms")).entrySet().stream() - .map(e -> LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue())) + .map(e -> LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue())) .collect(Collectors.toSet()) ); } @@ -535,7 +534,7 @@ public class MongoDao extends AbstractDao { Map perms = revert((Map) d.get("perms")); for (Map.Entry e : perms.entrySet()) { - Node node = LegacyNodeFactory.fromSerializedNode(e.getKey(), e.getValue()); + Node node = LegacyNodeFactory.fromLegacyString(e.getKey(), e.getValue()); if (!node.getPermission().equalsIgnoreCase(permission)) { continue; } @@ -755,39 +754,8 @@ public class MongoDao extends AbstractDao { Map m = new HashMap<>(); for (Node node : nodes) { //noinspection deprecation - m.put(toSerializedNode(node), node.getValuePrimitive()); + m.put(LegacyNodeFactory.toSerializedNode(node), node.getValuePrimitive()); } return m; } - - private static final String[] SERVER_WORLD_DELIMITERS = new String[]{"/", "-"}; - - private static String toSerializedNode(Node node) { - StringBuilder builder = new StringBuilder(); - - if (node.getServer().orElse(null) != null) { - builder.append(NodeFactory.escapeDelimiters(node.getServer().orElse(null), SERVER_WORLD_DELIMITERS)); - if (node.getWorld().orElse(null) != null) { - builder.append("-").append(NodeFactory.escapeDelimiters(node.getWorld().orElse(null), SERVER_WORLD_DELIMITERS)); - } - builder.append("/"); - } else { - if (node.getWorld().orElse(null) != null) { - builder.append("global-").append(NodeFactory.escapeDelimiters(node.getWorld().orElse(null), SERVER_WORLD_DELIMITERS)).append("/"); - } - } - - if (!node.getContexts().isEmpty()) { - builder.append("("); - for (Map.Entry entry : node.getContexts().toSet()) { - builder.append(NodeFactory.escapeDelimiters(entry.getKey(), "=", "(", ")", ",")).append("=").append(NodeFactory.escapeDelimiters(entry.getValue(), "=", "(", ")", ",")).append(","); - } - builder.deleteCharAt(builder.length() - 1); - builder.append(")"); - } - - builder.append(NodeFactory.escapeDelimiters(node.getPermission(), "/", "-", "$", "(", ")", "=", ",")); - if (node.isTemporary()) builder.append("$").append(node.getExpiryUnixTime()); - return builder.toString(); - } }