@Override public Map<String, Boolean> getPermissions(Set<Context> contexts) { NodeTree perms = this.permissions.get(contexts); return perms == null ? Collections.emptyMap() : perms.asMap(); }
@Override public CompletableFuture<Boolean> setPermission(Set<Context> contexts, String permission, Tristate value) { contexts = ImmutableSet.copyOf(contexts); while (true) { NodeTree oldTree = this.permissions.get(contexts); if (oldTree != null && oldTree.get(permission) == value) { return CompletableFuture.completedFuture(false); } if (oldTree == null && value != Tristate.UNDEFINED) { if (this.permissions.putIfAbsent(contexts, NodeTree.of(ImmutableMap.of(permission, value.asBoolean()))) == null) { break; } } else { if (oldTree == null || this.permissions.replace(contexts, oldTree, oldTree.withValue(permission, value))) { break; } } } return CompletableFuture.completedFuture(true); }
/** * Return a new NodeTree instance with a single changed value. * * @param node The node path to change the value of * @param value The value to change, or UNDEFINED to remove * @return The new, modified node tree */ public NodeTree withValue(String node, Tristate value) { Iterable<String> parts = NODE_SPLITTER.split(node.toLowerCase()); Node newRoot = new Node(new HashMap<>(this.rootNode.children)); Node newPtr = newRoot; Node currentPtr = this.rootNode; newPtr.value = currentPtr == null ? Tristate.UNDEFINED : currentPtr.value; for (String part : parts) { Node oldChild = currentPtr == null ? null : currentPtr.children.get(part); Node newChild = new Node(oldChild != null ? new HashMap<>(oldChild.children) : new HashMap<>()); newPtr.children.put(part, newChild); currentPtr = oldChild; newPtr = newChild; } newPtr.value = value; return new NodeTree(newRoot); }
@Test public void testWithAll() throws Exception { final Map<String, Boolean> testPermissions = new HashMap<>(); testPermissions.put("generate.rainbow", true); testPermissions.put("generate.sunset", false); testPermissions.put("generate", true); testPermissions.put("generate.thunderstorm.explosive", false); NodeTree oldTree = NodeTree.of(testPermissions); final Map<String, Tristate> newPermissions = new HashMap<>(); newPermissions.put("generate.sunset.red", Tristate.TRUE); newPermissions.put("generate.thunderstorm.explosive", Tristate.UNDEFINED); newPermissions.put("something.new", Tristate.FALSE); NodeTree newTree = oldTree.withAll(newPermissions); assertEquals(Tristate.FALSE, oldTree.get("generate.sunset.red")); assertEquals(Tristate.TRUE, newTree.get("generate.sunset.red")); assertEquals(Tristate.FALSE, oldTree.get("generate.thunderstorm.explosive")); assertEquals(Tristate.UNDEFINED, newTree.get("generate.thunderstorm.explosive")); assertEquals(Tristate.UNDEFINED, oldTree.get("something.new")); assertEquals(Tristate.FALSE, newTree.get("something.new")); }
@Test public void testAsMap() { final Map<String, Boolean> testPermissions = new HashMap<>(); testPermissions.put("generate.rainbow", true); testPermissions.put("generate.sunset", false); testPermissions.put("generate", true); testPermissions.put("generate.thunderstorm.explosive", false); NodeTree oldTree = NodeTree.of(testPermissions); assertEquals(testPermissions, oldTree.asMap()); }
@Test public void testCreateFromValues() throws Exception { final Map<String, Boolean> testPermissions = new HashMap<>(); testPermissions.put("generate.rainbow", true); testPermissions.put("generate.sunset", false); testPermissions.put("generate", true); testPermissions.put("generate.thunderstorm.explosive", false); NodeTree nodes = NodeTree.of(testPermissions, Tristate.UNDEFINED); assertEquals(Tristate.TRUE, nodes.get("generate.rainbow")); assertEquals(Tristate.TRUE, nodes.get("generate.rainbow.double")); assertEquals(Tristate.FALSE, nodes.get("generate.sunset")); assertEquals(Tristate.FALSE, nodes.get("generate.sunset.east")); assertEquals(Tristate.TRUE, nodes.get("generate.thunderstorm")); assertEquals(Tristate.FALSE, nodes.get("generate.thunderstorm.explosive")); assertEquals(Tristate.UNDEFINED, nodes.get("random.perm")); } }
/** * Create a new node tree with the given values, and a default value of * {@link Tristate#UNDEFINED}. * * @param values The values to set * @return The new node tree */ public static NodeTree of(Map<String, Boolean> values) { return of(values, Tristate.UNDEFINED); }
/** * Return a modified new node tree with the specified values set. * * @param values The values to set * @return The new node tree */ public NodeTree withAll(Map<String, Tristate> values) { NodeTree ret = this; for (Map.Entry<String, Tristate> ent : values.entrySet()) { ret = ret.withValue(ent.getKey(), ent.getValue()); } return ret; }
/** * Convert this node tree into a map of the defined nodes in this tree. * * @return An immutable map representation of the nodes defined in this tree */ public Map<String, Boolean> asMap() { ImmutableMap.Builder<String, Boolean> ret = ImmutableMap.builder(); for (Map.Entry<String, Node> ent : this.rootNode.children.entrySet()) { populateMap(ret, ent.getKey(), ent.getValue()); } return ret.build(); }
/** * Gets the calculated node tree representation of the permissions for this * subject data instance. If no data is present for the given context, * returns null. * * @param contexts The contexts to get a node tree for * @return The node tree */ public NodeTree getNodeTree(Set<Context> contexts) { NodeTree perms = this.permissions.get(contexts); return perms == null ? NodeTree.of(Collections.emptyMap()) : perms; }
/** * Return a modified new node tree with the specified values set. * * @param values The values to set * @return The new node tree */ public NodeTree withAll(Map<String, Tristate> values) { NodeTree ret = this; for (Map.Entry<String, Tristate> ent : values.entrySet()) { ret = ret.withValue(ent.getKey(), ent.getValue()); } return ret; }
private void populateMap(ImmutableMap.Builder<String, Boolean> values, String prefix, Node currentNode) { if (currentNode.value != Tristate.UNDEFINED) { values.put(prefix, currentNode.value.asBoolean()); } for (Map.Entry<String, Node> ent : currentNode.children.entrySet()) { populateMap(values, prefix + '.' + ent.getKey(), ent.getValue()); } }
@Test public void testWithValue() throws Exception { final Map<String, Boolean> testPermissions = new HashMap<>(); testPermissions.put("generate.rainbow", true); testPermissions.put("generate.sunset", false); testPermissions.put("generate", true); testPermissions.put("generate.thunderstorm.explosive", false); NodeTree oldTree = NodeTree.of(testPermissions); assertEquals(Tristate.FALSE, oldTree.get("generate.thunderstorm.explosive")); NodeTree newTree = oldTree.withValue("generate.thunderstorm.explosive", Tristate.TRUE); assertEquals(Tristate.FALSE, oldTree.get("generate.thunderstorm.explosive")); assertEquals(Tristate.TRUE, newTree.get("generate.thunderstorm.explosive")); }
@Override public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() { ImmutableMap.Builder<Set<Context>, Map<String, Boolean>> ret = ImmutableMap.builder(); for (Map.Entry<Set<Context>, NodeTree> ent : this.permissions.entrySet()) { ret.put(ent.getKey(), ent.getValue().asMap()); } return ret.build(); }
/** * Create a new node tree with the given values, and a default value of UNDEFINED. * * @param values The values to set * @return The new node tree */ public static NodeTree of(Map<String, Boolean> values) { return of(values, Tristate.UNDEFINED); }
/** * Convert this node tree into a map of the defined nodes in this tree. * * @return An immutable map representation of the nodes defined in this tree */ public Map<String, Boolean> asMap() { ImmutableMap.Builder<String, Boolean> ret = ImmutableMap.builder(); for (Map.Entry<String, Node> ent : this.rootNode.children.entrySet()) { populateMap(ret, ent.getKey(), ent.getValue()); } return ret.build(); }
/** * Create a new node tree with the given values, and the specified root * fallback value. * * @param values The values to be contained in this node tree * @param defaultValue The fallback value for any completely undefined nodes * @return The newly created node tree */ public static NodeTree of(Map<String, Boolean> values, Tristate defaultValue) { NodeTree newTree = new NodeTree(defaultValue); for (Map.Entry<String, Boolean> value : values.entrySet()) { Iterable<String> parts = NODE_SPLITTER.split(value.getKey().toLowerCase()); Node currentNode = newTree.rootNode; for (String part : parts) { if (currentNode.children.containsKey(part)) { currentNode = currentNode.children.get(part); } else { Node newNode = new Node(new HashMap<>()); currentNode.children.put(part, newNode); currentNode = newNode; } } currentNode.value = Tristate.fromBoolean(value.getValue()); } return newTree; }
@Override public boolean setPermission(Set<Context> contexts, String permission, Tristate value) { contexts = ImmutableSet.copyOf(contexts); while (true) { NodeTree oldTree = this.permissions.get(contexts); if (oldTree != null && oldTree.get(permission) == value) { return false; } if (oldTree == null && value != Tristate.UNDEFINED) { if (this.permissions.putIfAbsent(contexts, NodeTree.of(ImmutableMap.of(permission, value.asBoolean()))) == null) { break; } } else { if (oldTree == null || this.permissions.replace(contexts, oldTree, oldTree.withValue(permission, value))) { break; } } } return true; }
@Override public Map<String, Boolean> getPermissions(Set<Context> contexts) { NodeTree perms = this.permissions.get(contexts); return perms == null ? Collections.emptyMap() : perms.asMap(); }
/** * Get the calculated node tree representation of the permissions for this subject data instance. * If no data is present for the given context, returns null. * * @param contexts The contexts to get a node tree for * @return The node tree */ public NodeTree getNodeTree(Set<Context> contexts) { NodeTree perms = this.permissions.get(contexts); return perms == null ? NodeTree.of(Collections.emptyMap()) : perms; }