Mode storage refactoring - write group nodes into their own section in flatfile types (#502)

This commit is contained in:
Luck 2017-10-22 14:22:52 +01:00
parent f109cb684a
commit 26c813c07b
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
27 changed files with 793 additions and 588 deletions

View File

@ -39,6 +39,7 @@ import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.CommandPermission; import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.locale.CommandSpec; import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
@ -176,7 +177,7 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
for (NodeModel node : nodes) { for (NodeModel node : nodes) {
JsonObject attributes = new JsonObject(); JsonObject attributes = new JsonObject();
attributes.addProperty("permission", node.getPermission()); attributes.addProperty("permission", node.getPermission());
attributes.addProperty("value", node.isValue()); attributes.addProperty("value", node.getValue());
if (!node.getServer().equals("global")) { if (!node.getServer().equals("global")) {
attributes.addProperty("server", node.getServer()); attributes.addProperty("server", node.getServer());
@ -191,7 +192,7 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
} }
if (!node.getContexts().isEmpty()) { if (!node.getContexts().isEmpty()) {
attributes.add("context", node.getContextsAsJson()); attributes.add("context", ContextSetJsonSerializer.serializeContextSet(node.getContexts()));
} }
arr.add(attributes); arr.add(attributes);

View File

@ -40,6 +40,7 @@ import me.lucko.luckperms.common.commands.abstraction.SingleCommand;
import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util; import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.CommandPermission; import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.locale.CommandSpec; import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
@ -191,7 +192,7 @@ public class ApplyEditsCommand extends SingleCommand {
if (data.has("context") && data.get("context").isJsonObject()) { if (data.has("context") && data.get("context").isJsonObject()) {
JsonObject contexts = data.get("context").getAsJsonObject(); JsonObject contexts = data.get("context").getAsJsonObject();
context = NodeModel.deserializeContextSet(contexts).makeImmutable(); context = ContextSetJsonSerializer.deserializeContextSet(contexts).makeImmutable();
} }
nodes.add(NodeModel.of(permission, value, server, world, expiry, context)); nodes.add(NodeModel.of(permission, value, server, world, expiry, context));

View File

@ -34,7 +34,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@ -75,16 +75,16 @@ public class ContextsFile {
JsonObject data = new Gson().fromJson(reader, JsonObject.class); JsonObject data = new Gson().fromJson(reader, JsonObject.class);
if (data.has("context")) { if (data.has("context")) {
staticContexts = NodeModel.deserializeContextSet(data.get("context").getAsJsonObject()).makeImmutable(); staticContexts = ContextSetJsonSerializer.deserializeContextSet(data.get("context").getAsJsonObject()).makeImmutable();
save = true; save = true;
} }
if (data.has("static-contexts")) { if (data.has("static-contexts")) {
staticContexts = NodeModel.deserializeContextSet(data.get("static-contexts").getAsJsonObject()).makeImmutable(); staticContexts = ContextSetJsonSerializer.deserializeContextSet(data.get("static-contexts").getAsJsonObject()).makeImmutable();
} }
if (data.has("default-contexts")) { if (data.has("default-contexts")) {
defaultContexts = NodeModel.deserializeContextSet(data.get("default-contexts").getAsJsonObject()).makeImmutable(); defaultContexts = ContextSetJsonSerializer.deserializeContextSet(data.get("default-contexts").getAsJsonObject()).makeImmutable();
} }
} catch (IOException e) { } catch (IOException e) {
@ -102,8 +102,8 @@ public class ContextsFile {
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) { try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
JsonObject data = new JsonObject(); JsonObject data = new JsonObject();
data.add("static-contexts", NodeModel.serializeContextSet(staticContexts)); data.add("static-contexts", ContextSetJsonSerializer.serializeContextSet(staticContexts));
data.add("default-contexts", NodeModel.serializeContextSet(defaultContexts)); data.add("default-contexts", ContextSetJsonSerializer.serializeContextSet(defaultContexts));
new GsonBuilder().setPrettyPrinting().create().toJson(data, writer); new GsonBuilder().setPrettyPrinting().create().toJson(data, writer);
writer.flush(); writer.flush();

View File

@ -0,0 +1,86 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.common.contexts;
import lombok.experimental.UtilityClass;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.SimpleConfigurationNode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@UtilityClass
public class ContextSetConfigurateSerializer {
public static ConfigurationNode serializeContextSet(ContextSet contextSet) {
ConfigurationNode data = SimpleConfigurationNode.root();
Map<String, Collection<String>> map = contextSet.toMultimap().asMap();
map.forEach((k, v) -> {
List<String> values = new ArrayList<>(v);
int size = values.size();
if (size == 1) {
data.getNode(k).setValue(values.get(0));
} else if (size > 1) {
data.getNode(k).setValue(values);
}
});
return data;
}
public static MutableContextSet deserializeContextSet(ConfigurationNode data) {
Preconditions.checkArgument(data.hasMapChildren());
Map<Object, ? extends ConfigurationNode> dataMap = data.getChildrenMap();
MutableContextSet map = MutableContextSet.create();
for (Map.Entry<Object, ? extends ConfigurationNode> e : dataMap.entrySet()) {
String k = e.getKey().toString();
ConfigurationNode v = e.getValue();
if (v.hasListChildren()) {
List<? extends ConfigurationNode> values = v.getChildrenList();
for (ConfigurationNode value : values) {
map.add(k, value.getString());
}
} else {
map.add(k, v.getString());
}
}
return map;
}
}

View File

@ -0,0 +1,90 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.common.contexts;
import lombok.experimental.UtilityClass;
import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@UtilityClass
public class ContextSetJsonSerializer {
public static JsonObject serializeContextSet(ContextSet contextSet) {
JsonObject data = new JsonObject();
Map<String, Collection<String>> map = contextSet.toMultimap().asMap();
map.forEach((k, v) -> {
List<String> values = new ArrayList<>(v);
int size = values.size();
if (size == 1) {
data.addProperty(k, values.get(0));
} else if (size > 1) {
JsonArray arr = new JsonArray();
for (String s : values) {
arr.add(new JsonPrimitive(s));
}
data.add(k, arr);
}
});
return data;
}
public static MutableContextSet deserializeContextSet(JsonElement element) {
Preconditions.checkArgument(element.isJsonObject());
JsonObject data = element.getAsJsonObject();
MutableContextSet map = MutableContextSet.create();
for (Map.Entry<String, JsonElement> e : data.entrySet()) {
String k = e.getKey();
JsonElement v = e.getValue();
if (v.isJsonArray()) {
JsonArray values = v.getAsJsonArray();
for (JsonElement value : values) {
map.add(k, value.getAsString());
}
} else {
map.add(k, v.getAsString());
}
}
return map;
}
}

View File

@ -25,44 +25,21 @@
package me.lucko.luckperms.common.node; package me.lucko.luckperms.common.node;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.ToString;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/** /**
* An stripped down version of {@link Node}, without methods and cached values for handling permission lookups. * An stripped down version of {@link Node}, without methods and cached values
* for handling permission lookups.
* *
* All values are non-null. * All values are non-null.
*/ */
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public final class NodeModel { public final class NodeModel {
private static final Gson GSON = new Gson();
public static NodeModel fromNode(Node node) { public static NodeModel fromNode(Node node) {
return NodeModel.of( NodeModel model = of(
node.getPermission(), node.getPermission(),
node.getValuePrimitive(), node.getValuePrimitive(),
node.getServer().orElse("global"), node.getServer().orElse("global"),
@ -70,42 +47,67 @@ public final class NodeModel {
node.isTemporary() ? node.getExpiryUnixTime() : 0L, node.isTemporary() ? node.getExpiryUnixTime() : 0L,
node.getContexts().makeImmutable() node.getContexts().makeImmutable()
); );
model.node = node;
return model;
} }
public static NodeModel deserialize(String permission, boolean value, String server, String world, long expiry, String contexts) { public static NodeModel of(String permission, boolean value, String server, String world, long expiry, ImmutableContextSet contexts) {
JsonObject context = GSON.fromJson(contexts, JsonObject.class); return new NodeModel(permission, value, server, world, expiry, contexts);
return of(permission, value, server, world, expiry, deserializeContextSet(context).makeImmutable());
} }
@NonNull
private final String permission; private final String permission;
@NonNull
private final boolean value; private final boolean value;
@NonNull
private final String server; private final String server;
@NonNull
private final String world; private final String world;
@NonNull
private final long expiry; private final long expiry;
@NonNull
private final ImmutableContextSet contexts; private final ImmutableContextSet contexts;
private Node node = null;
public String serializeContext() { private NodeModel(@NonNull String permission, boolean value, @NonNull String server, @NonNull String world, long expiry, @NonNull ImmutableContextSet contexts) {
return GSON.toJson(getContextsAsJson()); this.permission = permission;
this.value = value;
this.server = server;
this.world = world;
this.expiry = expiry;
this.contexts = contexts;
} }
public JsonObject getContextsAsJson() { public synchronized Node toNode() {
return serializeContextSet(contexts); if (node == null) {
Node.Builder builder = NodeFactory.newBuilder(permission);
builder.setValue(value);
builder.setServer(server);
builder.setWorld(world);
builder.setExpiry(expiry);
builder.withExtraContext(contexts);
node = builder.build();
}
return node;
} }
public Node toNode() { public String getPermission() {
Node.Builder builder = NodeFactory.newBuilder(permission); return this.permission;
builder.setValue(value); }
builder.setServer(server);
builder.setWorld(world); public boolean getValue() {
builder.setExpiry(expiry); return this.value;
builder.withExtraContext(contexts); }
return builder.build();
public String getServer() {
return this.server;
}
public String getWorld() {
return this.world;
}
public long getExpiry() {
return this.expiry;
}
public ImmutableContextSet getContexts() {
return this.contexts;
} }
public NodeModel setPermission(String permission) { public NodeModel setPermission(String permission) {
@ -132,47 +134,38 @@ public final class NodeModel {
return of(permission, value, server, world, expiry, contexts); return of(permission, value, server, world, expiry, contexts);
} }
public static JsonObject serializeContextSet(ContextSet contextSet) { public boolean equals(Object o) {
JsonObject data = new JsonObject(); if (o == this) return true;
Map<String, Collection<String>> map = contextSet.toMultimap().asMap(); if (!(o instanceof NodeModel)) return false;
final NodeModel other = (NodeModel) o;
map.forEach((k, v) -> { return this.getPermission().equals(other.getPermission()) &&
List<String> values = new ArrayList<>(v); this.getValue() == other.getValue() &&
int size = values.size(); this.getServer().equals(other.getServer()) &&
this.getWorld().equals(other.getWorld()) &&
if (size == 1) { this.getExpiry() == other.getExpiry() &&
data.addProperty(k, values.get(0)); this.getContexts().equals(other.getContexts());
} else if (size > 1) {
JsonArray arr = new JsonArray();
for (String s : values) {
arr.add(new JsonPrimitive(s));
}
data.add(k, arr);
}
});
return data;
} }
public static MutableContextSet deserializeContextSet(JsonElement element) { public int hashCode() {
Preconditions.checkArgument(element.isJsonObject()); final int PRIME = 59;
JsonObject data = element.getAsJsonObject(); int result = 1;
result = result * PRIME + this.getPermission().hashCode();
ImmutableSetMultimap.Builder<String, String> map = ImmutableSetMultimap.builder(); result = result * PRIME + Boolean.hashCode(this.getValue());
for (Map.Entry<String, JsonElement> e : data.entrySet()) { result = result * PRIME + this.getServer().hashCode();
String k = e.getKey(); result = result * PRIME + this.getWorld().hashCode();
JsonElement v = e.getValue(); result = result * PRIME + Long.hashCode(this.getExpiry());
if (v.isJsonArray()) { result = result * PRIME + this.getContexts().hashCode();
JsonArray values = v.getAsJsonArray(); return result;
for (JsonElement value : values) {
map.put(k, value.getAsString());
}
} else {
map.put(k, v.getAsString());
}
}
return MutableContextSet.fromMultimap(map.build());
} }
public String toString() {
return "NodeModel(" +
"permission=" + this.getPermission() + ", " +
"value=" + this.getValue() + ", " +
"server=" + this.getServer() + ", " +
"world=" + this.getWorld() + ", " +
"expiry=" + this.getExpiry() + ", " +
"contexts=" + this.getContexts() + ")";
}
} }

View File

@ -41,7 +41,7 @@ import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.backing.AbstractBacking; import me.lucko.luckperms.common.storage.backing.AbstractDao;
import me.lucko.luckperms.common.storage.wrappings.BufferedOutputStorage; import me.lucko.luckperms.common.storage.wrappings.BufferedOutputStorage;
import me.lucko.luckperms.common.storage.wrappings.PhasedStorage; import me.lucko.luckperms.common.storage.wrappings.PhasedStorage;
@ -53,11 +53,11 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* Converts a {@link AbstractBacking} to use {@link CompletableFuture}s * Converts a {@link AbstractDao} to use {@link CompletableFuture}s
*/ */
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class AbstractStorage implements Storage { public class AbstractStorage implements Storage {
public static Storage wrap(LuckPermsPlugin plugin, AbstractBacking backing) { public static Storage create(LuckPermsPlugin plugin, AbstractDao backing) {
BufferedOutputStorage bufferedDs = BufferedOutputStorage.wrap(PhasedStorage.wrap(new AbstractStorage(plugin, backing)), 250L); BufferedOutputStorage bufferedDs = BufferedOutputStorage.wrap(PhasedStorage.wrap(new AbstractStorage(plugin, backing)), 250L);
plugin.getScheduler().asyncRepeating(bufferedDs, 2L); plugin.getScheduler().asyncRepeating(bufferedDs, 2L);
return bufferedDs; return bufferedDs;
@ -66,19 +66,19 @@ public class AbstractStorage implements Storage {
private final LuckPermsPlugin plugin; private final LuckPermsPlugin plugin;
@Delegate(types = Delegated.class) @Delegate(types = Delegated.class)
private final AbstractBacking backing; private final AbstractDao dao;
@Getter @Getter
private final StorageDelegate delegate; private final StorageDelegate delegate;
private AbstractStorage(LuckPermsPlugin plugin, AbstractBacking backing) { private AbstractStorage(LuckPermsPlugin plugin, AbstractDao dao) {
this.plugin = plugin; this.plugin = plugin;
this.backing = backing; this.dao = dao;
this.delegate = new StorageDelegate(plugin, this); this.delegate = new StorageDelegate(plugin, this);
} }
private <T> CompletableFuture<T> makeFuture(Supplier<T> supplier) { private <T> CompletableFuture<T> makeFuture(Supplier<T> supplier) {
return CompletableFuture.supplyAsync(supplier, backing.getPlugin().getScheduler().async()); return CompletableFuture.supplyAsync(supplier, dao.getPlugin().getScheduler().async());
} }
@Override @Override
@ -88,23 +88,23 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> logAction(LogEntry entry) { public CompletableFuture<Boolean> logAction(LogEntry entry) {
return makeFuture(() -> backing.logAction(entry)); return makeFuture(() -> dao.logAction(entry));
} }
@Override @Override
public CompletableFuture<Log> getLog() { public CompletableFuture<Log> getLog() {
return makeFuture(backing::getLog); return makeFuture(dao::getLog);
} }
@Override @Override
public CompletableFuture<Boolean> applyBulkUpdate(BulkUpdate bulkUpdate) { public CompletableFuture<Boolean> applyBulkUpdate(BulkUpdate bulkUpdate) {
return makeFuture(() -> backing.applyBulkUpdate(bulkUpdate)); return makeFuture(() -> dao.applyBulkUpdate(bulkUpdate));
} }
@Override @Override
public CompletableFuture<Boolean> loadUser(UUID uuid, String username) { public CompletableFuture<Boolean> loadUser(UUID uuid, String username) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.loadUser(uuid, username)) { if (dao.loadUser(uuid, username)) {
User u = plugin.getUserManager().getIfLoaded(uuid); User u = plugin.getUserManager().getIfLoaded(uuid);
if (u != null) { if (u != null) {
plugin.getApiProvider().getEventFactory().handleUserLoad(u); plugin.getApiProvider().getEventFactory().handleUserLoad(u);
@ -117,23 +117,23 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> saveUser(User user) { public CompletableFuture<Boolean> saveUser(User user) {
return makeFuture(() -> backing.saveUser(user)); return makeFuture(() -> dao.saveUser(user));
} }
@Override @Override
public CompletableFuture<Set<UUID>> getUniqueUsers() { public CompletableFuture<Set<UUID>> getUniqueUsers() {
return makeFuture(backing::getUniqueUsers); return makeFuture(dao::getUniqueUsers);
} }
@Override @Override
public CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(String permission) { public CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(String permission) {
return makeFuture(() -> backing.getUsersWithPermission(permission)); return makeFuture(() -> dao.getUsersWithPermission(permission));
} }
@Override @Override
public CompletableFuture<Boolean> createAndLoadGroup(String name, CreationCause cause) { public CompletableFuture<Boolean> createAndLoadGroup(String name, CreationCause cause) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.createAndLoadGroup(name)) { if (dao.createAndLoadGroup(name)) {
Group g = plugin.getGroupManager().getIfLoaded(name); Group g = plugin.getGroupManager().getIfLoaded(name);
if (g != null) { if (g != null) {
plugin.getApiProvider().getEventFactory().handleGroupCreate(g, cause); plugin.getApiProvider().getEventFactory().handleGroupCreate(g, cause);
@ -147,7 +147,7 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> loadGroup(String name) { public CompletableFuture<Boolean> loadGroup(String name) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.loadGroup(name)) { if (dao.loadGroup(name)) {
Group g = plugin.getGroupManager().getIfLoaded(name); Group g = plugin.getGroupManager().getIfLoaded(name);
if (g != null) { if (g != null) {
plugin.getApiProvider().getEventFactory().handleGroupLoad(g); plugin.getApiProvider().getEventFactory().handleGroupLoad(g);
@ -161,7 +161,7 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> loadAllGroups() { public CompletableFuture<Boolean> loadAllGroups() {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.loadAllGroups()) { if (dao.loadAllGroups()) {
plugin.getApiProvider().getEventFactory().handleGroupLoadAll(); plugin.getApiProvider().getEventFactory().handleGroupLoadAll();
return true; return true;
} }
@ -171,13 +171,13 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> saveGroup(Group group) { public CompletableFuture<Boolean> saveGroup(Group group) {
return makeFuture(() -> backing.saveGroup(group)); return makeFuture(() -> dao.saveGroup(group));
} }
@Override @Override
public CompletableFuture<Boolean> deleteGroup(Group group, DeletionCause cause) { public CompletableFuture<Boolean> deleteGroup(Group group, DeletionCause cause) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.deleteGroup(group)) { if (dao.deleteGroup(group)) {
plugin.getApiProvider().getEventFactory().handleGroupDelete(group, cause); plugin.getApiProvider().getEventFactory().handleGroupDelete(group, cause);
return true; return true;
} }
@ -187,13 +187,13 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(String permission) { public CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(String permission) {
return makeFuture(() -> backing.getGroupsWithPermission(permission)); return makeFuture(() -> dao.getGroupsWithPermission(permission));
} }
@Override @Override
public CompletableFuture<Boolean> createAndLoadTrack(String name, CreationCause cause) { public CompletableFuture<Boolean> createAndLoadTrack(String name, CreationCause cause) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.createAndLoadTrack(name)) { if (dao.createAndLoadTrack(name)) {
Track t = plugin.getTrackManager().getIfLoaded(name); Track t = plugin.getTrackManager().getIfLoaded(name);
if (t != null) { if (t != null) {
plugin.getApiProvider().getEventFactory().handleTrackCreate(t, cause); plugin.getApiProvider().getEventFactory().handleTrackCreate(t, cause);
@ -207,7 +207,7 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> loadTrack(String name) { public CompletableFuture<Boolean> loadTrack(String name) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.loadTrack(name)) { if (dao.loadTrack(name)) {
Track t = plugin.getTrackManager().getIfLoaded(name); Track t = plugin.getTrackManager().getIfLoaded(name);
if (t != null) { if (t != null) {
plugin.getApiProvider().getEventFactory().handleTrackLoad(t); plugin.getApiProvider().getEventFactory().handleTrackLoad(t);
@ -221,7 +221,7 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> loadAllTracks() { public CompletableFuture<Boolean> loadAllTracks() {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.loadAllTracks()) { if (dao.loadAllTracks()) {
plugin.getApiProvider().getEventFactory().handleTrackLoadAll(); plugin.getApiProvider().getEventFactory().handleTrackLoadAll();
return true; return true;
} }
@ -231,13 +231,13 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> saveTrack(Track track) { public CompletableFuture<Boolean> saveTrack(Track track) {
return makeFuture(() -> backing.saveTrack(track)); return makeFuture(() -> dao.saveTrack(track));
} }
@Override @Override
public CompletableFuture<Boolean> deleteTrack(Track track, DeletionCause cause) { public CompletableFuture<Boolean> deleteTrack(Track track, DeletionCause cause) {
return makeFuture(() -> { return makeFuture(() -> {
if (backing.deleteTrack(track)) { if (dao.deleteTrack(track)) {
plugin.getApiProvider().getEventFactory().handleTrackDelete(track, cause); plugin.getApiProvider().getEventFactory().handleTrackDelete(track, cause);
return true; return true;
} }
@ -247,17 +247,17 @@ public class AbstractStorage implements Storage {
@Override @Override
public CompletableFuture<Boolean> saveUUIDData(UUID uuid, String username) { public CompletableFuture<Boolean> saveUUIDData(UUID uuid, String username) {
return makeFuture(() -> backing.saveUUIDData(uuid, username)); return makeFuture(() -> dao.saveUUIDData(uuid, username));
} }
@Override @Override
public CompletableFuture<UUID> getUUID(String username) { public CompletableFuture<UUID> getUUID(String username) {
return makeFuture(() -> backing.getUUID(username)); return makeFuture(() -> dao.getUUID(username));
} }
@Override @Override
public CompletableFuture<String> getName(UUID uuid) { public CompletableFuture<String> getName(UUID uuid) {
return makeFuture(() -> backing.getName(uuid)); return makeFuture(() -> dao.getName(uuid));
} }
private interface Delegated { private interface Delegated {

View File

@ -35,7 +35,7 @@ import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.backing.AbstractBacking; import me.lucko.luckperms.common.storage.backing.AbstractDao;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -43,11 +43,11 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
public class SplitBacking extends AbstractBacking { public class SplitStorageDao extends AbstractDao {
private final Map<String, AbstractBacking> backing; private final Map<String, AbstractDao> backing;
private final Map<String, String> types; private final Map<String, String> types;
protected SplitBacking(LuckPermsPlugin plugin, Map<String, AbstractBacking> backing, Map<String, String> types) { protected SplitStorageDao(LuckPermsPlugin plugin, Map<String, AbstractDao> backing, Map<String, String> types) {
super(plugin, "Split Storage"); super(plugin, "Split Storage");
this.backing = ImmutableMap.copyOf(backing); this.backing = ImmutableMap.copyOf(backing);
this.types = ImmutableMap.copyOf(types); this.types = ImmutableMap.copyOf(types);
@ -56,8 +56,8 @@ public class SplitBacking extends AbstractBacking {
@Override @Override
public void init() { public void init() {
boolean success = true; boolean success = true;
backing.values().forEach(AbstractBacking::init); backing.values().forEach(AbstractDao::init);
for (AbstractBacking ds : backing.values()) { for (AbstractDao ds : backing.values()) {
if (!ds.isAcceptingLogins()) { if (!ds.isAcceptingLogins()) {
success = false; success = false;
} }
@ -68,14 +68,14 @@ public class SplitBacking extends AbstractBacking {
@Override @Override
public void shutdown() { public void shutdown() {
backing.values().forEach(AbstractBacking::shutdown); backing.values().forEach(AbstractDao::shutdown);
} }
@Override @Override
public Map<String, String> getMeta() { public Map<String, String> getMeta() {
Map<String, String> ret = new LinkedHashMap<>(); Map<String, String> ret = new LinkedHashMap<>();
ret.put("Types", types.toString()); ret.put("Types", types.toString());
for (AbstractBacking backing : backing.values()) { for (AbstractDao backing : backing.values()) {
ret.putAll(backing.getMeta()); ret.putAll(backing.getMeta());
} }
return ret; return ret;

View File

@ -31,16 +31,16 @@ import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.backing.AbstractBacking; import me.lucko.luckperms.common.storage.backing.AbstractDao;
import me.lucko.luckperms.common.storage.backing.file.HOCONBacking; import me.lucko.luckperms.common.storage.backing.file.HoconDao;
import me.lucko.luckperms.common.storage.backing.file.JSONBacking; import me.lucko.luckperms.common.storage.backing.file.JsonDao;
import me.lucko.luckperms.common.storage.backing.file.YAMLBacking; import me.lucko.luckperms.common.storage.backing.file.YamlDao;
import me.lucko.luckperms.common.storage.backing.mongodb.MongoDBBacking; import me.lucko.luckperms.common.storage.backing.mongodb.MongoDao;
import me.lucko.luckperms.common.storage.backing.sql.SQLBacking; import me.lucko.luckperms.common.storage.backing.sql.SqlDao;
import me.lucko.luckperms.common.storage.backing.sql.provider.H2Provider; import me.lucko.luckperms.common.storage.backing.sql.provider.file.H2ConnectionFactory;
import me.lucko.luckperms.common.storage.backing.sql.provider.MySQLProvider; import me.lucko.luckperms.common.storage.backing.sql.provider.file.SQLiteConnectionFactory;
import me.lucko.luckperms.common.storage.backing.sql.provider.PostgreSQLProvider; import me.lucko.luckperms.common.storage.backing.sql.provider.remote.MySqlConnectionFactory;
import me.lucko.luckperms.common.storage.backing.sql.provider.SQLiteProvider; import me.lucko.luckperms.common.storage.backing.sql.provider.remote.PostgreConnectionFactory;
import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.common.utils.ImmutableCollectors;
import java.io.File; import java.io.File;
@ -91,13 +91,13 @@ public class StorageFactory {
Set<String> neededTypes = new HashSet<>(); Set<String> neededTypes = new HashSet<>();
neededTypes.addAll(types.values()); neededTypes.addAll(types.values());
Map<String, AbstractBacking> backing = new HashMap<>(); Map<String, AbstractDao> backing = new HashMap<>();
for (String type : neededTypes) { for (String type : neededTypes) {
backing.put(type, makeBacking(StorageType.parse(type), plugin)); backing.put(type, makeDao(StorageType.parse(type), plugin));
} }
storage = AbstractStorage.wrap(plugin, new SplitBacking(plugin, backing, types)); storage = AbstractStorage.create(plugin, new SplitStorageDao(plugin, backing, types));
} else { } else {
String method = plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD); String method = plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
@ -115,52 +115,52 @@ public class StorageFactory {
} }
private static Storage makeInstance(StorageType type, LuckPermsPlugin plugin) { private static Storage makeInstance(StorageType type, LuckPermsPlugin plugin) {
return AbstractStorage.wrap(plugin, makeBacking(type, plugin)); return AbstractStorage.create(plugin, makeDao(type, plugin));
} }
private static AbstractBacking makeBacking(StorageType method, LuckPermsPlugin plugin) { private static AbstractDao makeDao(StorageType method, LuckPermsPlugin plugin) {
switch (method) { switch (method) {
case MARIADB: case MARIADB:
return new SQLBacking(plugin, new MySQLProvider( return new SqlDao(plugin, new MySqlConnectionFactory(
"MariaDB", "MariaDB",
"org.mariadb.jdbc.MySQLDataSource", "org.mariadb.jdbc.MySQLDataSource",
plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)), plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX) plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
); );
case MYSQL: case MYSQL:
return new SQLBacking(plugin, new MySQLProvider( return new SqlDao(plugin, new MySqlConnectionFactory(
"MySQL", "MySQL",
"com.mysql.jdbc.jdbc2.optional.MysqlDataSource", "com.mysql.jdbc.jdbc2.optional.MysqlDataSource",
plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)), plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX) plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
); );
case SQLITE: case SQLITE:
return new SQLBacking(plugin, new SQLiteProvider( return new SqlDao(plugin, new SQLiteConnectionFactory(
new File(plugin.getDataDirectory(), "luckperms-sqlite.db")), new File(plugin.getDataDirectory(), "luckperms-sqlite.db")),
plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX) plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
); );
case H2: case H2:
return new SQLBacking(plugin, new H2Provider( return new SqlDao(plugin, new H2ConnectionFactory(
new File(plugin.getDataDirectory(), "luckperms-h2")), new File(plugin.getDataDirectory(), "luckperms-h2")),
plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX) plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
); );
case POSTGRESQL: case POSTGRESQL:
return new SQLBacking(plugin, new PostgreSQLProvider( return new SqlDao(plugin, new PostgreConnectionFactory(
plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)), plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES)),
plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX) plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
); );
case MONGODB: case MONGODB:
return new MongoDBBacking( return new MongoDao(
plugin, plugin,
plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES), plugin.getConfiguration().get(ConfigKeys.DATABASE_VALUES),
plugin.getConfiguration().get(ConfigKeys.MONGODB_COLLECTION_PREFIX) plugin.getConfiguration().get(ConfigKeys.MONGODB_COLLECTION_PREFIX)
); );
case YAML: case YAML:
return new YAMLBacking(plugin, "yaml-storage"); return new YamlDao(plugin, "yaml-storage");
case HOCON: case HOCON:
return new HOCONBacking(plugin, "hocon-storage"); return new HoconDao(plugin, "hocon-storage");
default: default:
return new JSONBacking(plugin, "json-storage"); return new JsonDao(plugin, "json-storage");
} }
} }
} }

View File

@ -46,7 +46,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
@RequiredArgsConstructor(access = AccessLevel.PROTECTED) @RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class AbstractBacking { public abstract class AbstractDao {
@Getter @Getter
protected final LuckPermsPlugin plugin; protected final LuckPermsPlugin plugin;

View File

@ -27,22 +27,19 @@ package me.lucko.luckperms.common.storage.backing.file;
import lombok.Getter; import lombok.Getter;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.LogEntry; import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate; import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.commands.utils.Util; import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Constants; import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.contexts.ContextSetConfigurateSerializer;
import me.lucko.luckperms.common.managers.GenericUserManager; import me.lucko.luckperms.common.managers.GenericUserManager;
import me.lucko.luckperms.common.managers.GroupManager; import me.lucko.luckperms.common.managers.GroupManager;
import me.lucko.luckperms.common.managers.TrackManager; import me.lucko.luckperms.common.managers.TrackManager;
@ -53,9 +50,9 @@ import me.lucko.luckperms.common.node.NodeHeldPermission;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.UserIdentifier; import me.lucko.luckperms.common.references.UserIdentifier;
import me.lucko.luckperms.common.storage.backing.AbstractBacking; import me.lucko.luckperms.common.storage.backing.AbstractDao;
import me.lucko.luckperms.common.storage.backing.legacy.LegacyJSONSchemaMigration; import me.lucko.luckperms.common.storage.backing.legacy.LegacyJsonMigration;
import me.lucko.luckperms.common.storage.backing.legacy.LegacyYAMLSchemaMigration; import me.lucko.luckperms.common.storage.backing.legacy.LegacyYamlMigration;
import ninja.leaping.configurate.ConfigurationNode; import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.SimpleConfigurationNode; import ninja.leaping.configurate.SimpleConfigurationNode;
@ -67,6 +64,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -82,7 +80,7 @@ import java.util.logging.LogRecord;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public abstract class ConfigurateBacking extends AbstractBacking { public abstract class ConfigurateDao extends AbstractDao {
private static final String LOG_FORMAT = "%s(%s): [%s] %s(%s) --> %s"; private static final String LOG_FORMAT = "%s(%s): [%s] %s(%s) --> %s";
private final Logger actionLogger = Logger.getLogger("luckperms_actions"); private final Logger actionLogger = Logger.getLogger("luckperms_actions");
@ -100,7 +98,7 @@ public abstract class ConfigurateBacking extends AbstractBacking {
private File groupsDirectory; private File groupsDirectory;
private File tracksDirectory; private File tracksDirectory;
protected ConfigurateBacking(LuckPermsPlugin plugin, String name, String fileExtension, String dataFolderName) { protected ConfigurateDao(LuckPermsPlugin plugin, String name, String fileExtension, String dataFolderName) {
super(plugin, name); super(plugin, name);
this.fileExtension = fileExtension; this.fileExtension = fileExtension;
this.dataFolderName = dataFolderName; this.dataFolderName = dataFolderName;
@ -210,15 +208,15 @@ public abstract class ConfigurateBacking extends AbstractBacking {
plugin.getLog().severe("Starting migration from legacy schema. This could take a while...."); plugin.getLog().severe("Starting migration from legacy schema. This could take a while....");
plugin.getLog().severe("Please do not stop your server while the migration takes place."); plugin.getLog().severe("Please do not stop your server while the migration takes place.");
if (this instanceof YAMLBacking) { if (this instanceof YamlDao) {
try { try {
new LegacyYAMLSchemaMigration(plugin, (YAMLBacking) this, oldData, data).run(); new LegacyYamlMigration(plugin, (YamlDao) this, oldData, data).run();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} else if (this instanceof JSONBacking) { } else if (this instanceof JsonDao) {
try { try {
new LegacyJSONSchemaMigration(plugin, (JSONBacking) this, oldData, data).run(); new LegacyJsonMigration(plugin, (JsonDao) this, oldData, data).run();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -361,7 +359,7 @@ public abstract class ConfigurateBacking extends AbstractBacking {
reportException("bulk update", e); reportException("bulk update", e);
return false; return false;
} }
return false; return true;
} }
@Override @Override
@ -372,7 +370,7 @@ public abstract class ConfigurateBacking extends AbstractBacking {
ConfigurationNode object = readFile(StorageLocation.USER, uuid.toString()); ConfigurationNode object = readFile(StorageLocation.USER, uuid.toString());
if (object != null) { if (object != null) {
String name = object.getNode("name").getString(); String name = object.getNode("name").getString();
user.getPrimaryGroup().setStoredValue(object.getNode(this instanceof JSONBacking ? "primaryGroup" : "primary-group").getString()); user.getPrimaryGroup().setStoredValue(object.getNode(this instanceof JsonDao ? "primaryGroup" : "primary-group").getString());
Set<NodeModel> data = readNodes(object); Set<NodeModel> data = readNodes(object);
Set<Node> nodes = data.stream().map(NodeModel::toNode).collect(Collectors.toSet()); Set<Node> nodes = data.stream().map(NodeModel::toNode).collect(Collectors.toSet());
@ -412,7 +410,7 @@ public abstract class ConfigurateBacking extends AbstractBacking {
ConfigurationNode data = SimpleConfigurationNode.root(); ConfigurationNode data = SimpleConfigurationNode.root();
data.getNode("uuid").setValue(user.getUuid().toString()); data.getNode("uuid").setValue(user.getUuid().toString());
data.getNode("name").setValue(user.getName().orElse("null")); data.getNode("name").setValue(user.getName().orElse("null"));
data.getNode(this instanceof JSONBacking ? "primaryGroup" : "primary-group").setValue(user.getPrimaryGroup().getStoredValue().orElse("default")); data.getNode(this instanceof JsonDao ? "primaryGroup" : "primary-group").setValue(user.getPrimaryGroup().getStoredValue().orElse("default"));
Set<NodeModel> nodes = user.getEnduringNodes().values().stream().map(NodeModel::fromNode).collect(Collectors.toCollection(LinkedHashSet::new)); Set<NodeModel> nodes = user.getEnduringNodes().values().stream().map(NodeModel::fromNode).collect(Collectors.toCollection(LinkedHashSet::new));
writeNodes(data, nodes); writeNodes(data, nodes);
@ -499,8 +497,11 @@ public abstract class ConfigurateBacking extends AbstractBacking {
@Override @Override
public boolean loadGroup(String name) { public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().getOrMake(name); Group group = plugin.getGroupManager().getIfLoaded(name);
group.getIoLock().lock(); if (group != null) {
group.getIoLock().lock();
}
try { try {
ConfigurationNode object = readFile(StorageLocation.GROUP, name); ConfigurationNode object = readFile(StorageLocation.GROUP, name);
@ -508,6 +509,11 @@ public abstract class ConfigurateBacking extends AbstractBacking {
return false; return false;
} }
if (group == null) {
group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
}
Set<NodeModel> data = readNodes(object); Set<NodeModel> data = readNodes(object);
Set<Node> nodes = data.stream().map(NodeModel::toNode).collect(Collectors.toSet()); Set<Node> nodes = data.stream().map(NodeModel::toNode).collect(Collectors.toSet());
group.setEnduringNodes(nodes); group.setEnduringNodes(nodes);
@ -515,7 +521,9 @@ public abstract class ConfigurateBacking extends AbstractBacking {
} catch (Exception e) { } catch (Exception e) {
return reportException(name, e); return reportException(name, e);
} finally { } finally {
group.getIoLock().unlock(); if (group != null) {
group.getIoLock().unlock();
}
} }
return true; return true;
} }
@ -633,8 +641,11 @@ public abstract class ConfigurateBacking extends AbstractBacking {
@Override @Override
public boolean loadTrack(String name) { public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().getOrMake(name); Track track = plugin.getTrackManager().getIfLoaded(name);
track.getIoLock().lock(); if (track != null) {
track.getIoLock().lock();
}
try { try {
ConfigurationNode object = readFile(StorageLocation.TRACK, name); ConfigurationNode object = readFile(StorageLocation.TRACK, name);
@ -642,13 +653,20 @@ public abstract class ConfigurateBacking extends AbstractBacking {
return false; return false;
} }
if (track == null) {
track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
}
List<String> groups = object.getNode("groups").getList(TypeToken.of(String.class)); List<String> groups = object.getNode("groups").getList(TypeToken.of(String.class));
track.setGroups(groups); track.setGroups(groups);
} catch (Exception e) { } catch (Exception e) {
return reportException(name, e); return reportException(name, e);
} finally { } finally {
track.getIoLock().unlock(); if (track != null) {
track.getIoLock().unlock();
}
} }
return true; return true;
} }
@ -720,6 +738,45 @@ public abstract class ConfigurateBacking extends AbstractBacking {
return uuidCache.lookupUsername(uuid); return uuidCache.lookupUsername(uuid);
} }
private static Collection<NodeModel> readAttributes(ConfigurationNode entry, String permission) {
Map<Object, ? extends ConfigurationNode> attributes = entry.getChildrenMap();
boolean value = true;
String server = "global";
String world = "global";
long expiry = 0L;
ImmutableContextSet context = ImmutableContextSet.empty();
if (attributes.containsKey("value")) {
value = attributes.get("value").getBoolean();
}
if (attributes.containsKey("server")) {
server = attributes.get("server").getString();
}
if (attributes.containsKey("world")) {
world = attributes.get("world").getString();
}
if (attributes.containsKey("expiry")) {
expiry = attributes.get("expiry").getLong();
}
if (attributes.containsKey("context") && attributes.get("context").hasMapChildren()) {
ConfigurationNode contexts = attributes.get("context");
context = ContextSetConfigurateSerializer.deserializeContextSet(contexts).makeImmutable();
}
ConfigurationNode batchAttribute = attributes.get("permissions");
if (permission.startsWith("luckperms.batch") && batchAttribute != null && batchAttribute.hasListChildren()) {
List<NodeModel> nodes = new ArrayList<>();
for (ConfigurationNode element : batchAttribute.getChildrenList()) {
nodes.add(NodeModel.of(element.getString(), value, server, world, expiry, context));
}
return nodes;
} else {
return Collections.singleton(NodeModel.of(permission, value, server, world, expiry, context));
}
}
private static Set<NodeModel> readNodes(ConfigurationNode data) { private static Set<NodeModel> readNodes(ConfigurationNode data) {
Set<NodeModel> nodes = new HashSet<>(); Set<NodeModel> nodes = new HashSet<>();
@ -743,129 +800,102 @@ public abstract class ConfigurateBacking extends AbstractBacking {
} }
String permission = entry.getKey().toString(); String permission = entry.getKey().toString();
Map<Object, ? extends ConfigurationNode> attributes = entry.getValue().getChildrenMap(); nodes.addAll(readAttributes(entry.getValue(), permission));
}
}
boolean value = true; if (data.getNode("parents").hasListChildren()) {
String server = "global"; List<? extends ConfigurationNode> parts = data.getNode("parents").getChildrenList();
String world = "global";
long expiry = 0L;
ImmutableContextSet context = ImmutableContextSet.empty();
if (attributes.containsKey("value")) { for (ConfigurationNode ent : parts) {
value = attributes.get("value").getBoolean(); String stringValue = ent.getValue(Types::strictAsString);
} if (stringValue != null) {
if (attributes.containsKey("server")) { nodes.add(NodeModel.of("group." + stringValue, true, "global", "global", 0L, ImmutableContextSet.empty()));
server = attributes.get("server").getString(); continue;
}
if (attributes.containsKey("world")) {
world = attributes.get("world").getString();
}
if (attributes.containsKey("expiry")) {
expiry = attributes.get("expiry").getLong();
} }
if (attributes.containsKey("context") && attributes.get("context").hasMapChildren()) { if (!ent.hasMapChildren()) {
ConfigurationNode contexts = attributes.get("context"); continue;
context = deserializeContextSet(contexts).makeImmutable();
} }
final ConfigurationNode batchAttribute = attributes.get("permissions"); Map.Entry<Object, ? extends ConfigurationNode> entry = Iterables.getFirst(ent.getChildrenMap().entrySet(), null);
if (permission.startsWith("luckperms.batch") && batchAttribute != null && batchAttribute.hasListChildren()) { if (entry == null || !entry.getValue().hasMapChildren()) {
for (ConfigurationNode element : batchAttribute.getChildrenList()) { continue;
nodes.add(NodeModel.of(element.getString(), value, server, world, expiry, context));
}
} else {
nodes.add(NodeModel.of(permission, value, server, world, expiry, context));
} }
String permission = "group." + entry.getKey().toString();
nodes.addAll(readAttributes(entry.getValue(), permission));
} }
} }
return nodes; return nodes;
} }
private static ConfigurationNode writeAttributes(NodeModel node) {
ConfigurationNode attributes = SimpleConfigurationNode.root();
attributes.getNode("value").setValue(node.getValue());
if (!node.getServer().equals("global")) {
attributes.getNode("server").setValue(node.getServer());
}
if (!node.getWorld().equals("global")) {
attributes.getNode("world").setValue(node.getWorld());
}
if (node.getExpiry() != 0L) {
attributes.getNode("expiry").setValue(node.getExpiry());
}
if (!node.getContexts().isEmpty()) {
attributes.getNode("context").setValue(ContextSetConfigurateSerializer.serializeContextSet(node.getContexts()));
}
return attributes;
}
private static void writeNodes(ConfigurationNode to, Set<NodeModel> nodes) { private static void writeNodes(ConfigurationNode to, Set<NodeModel> nodes) {
ConfigurationNode arr = SimpleConfigurationNode.root(); ConfigurationNode permsSection = SimpleConfigurationNode.root();
ConfigurationNode parentsSection = SimpleConfigurationNode.root();
for (NodeModel node : nodes) { for (NodeModel node : nodes) {
// just a raw, default node. // just a raw, default node.
boolean single = node.isValue() && boolean single = node.getValue() &&
node.getServer().equalsIgnoreCase("global") && node.getServer().equalsIgnoreCase("global") &&
node.getWorld().equalsIgnoreCase("global") && node.getWorld().equalsIgnoreCase("global") &&
node.getExpiry() == 0L && node.getExpiry() == 0L &&
node.getContexts().isEmpty(); node.getContexts().isEmpty();
// try to parse out the group
String group = node.toNode().isGroupNode() ? node.toNode().getGroupName() : null;
// just add a string to the list. // just add a string to the list.
if (single) { if (single) {
arr.getAppendedNode().setValue(node.getPermission());
if (group != null) {
parentsSection.getAppendedNode().setValue(group);
continue;
}
permsSection.getAppendedNode().setValue(node.getPermission());
continue; continue;
} }
ConfigurationNode attributes = SimpleConfigurationNode.root(); if (group != null) {
attributes.getNode("value").setValue(node.isValue()); ConfigurationNode ent = SimpleConfigurationNode.root();
ent.getNode(group).setValue(writeAttributes(node));
if (!node.getServer().equals("global")) { parentsSection.getAppendedNode().setValue(ent);
attributes.getNode("server").setValue(node.getServer()); continue;
} }
if (!node.getWorld().equals("global")) { ConfigurationNode ent = SimpleConfigurationNode.root();
attributes.getNode("world").setValue(node.getWorld()); ent.getNode(node.getPermission()).setValue(writeAttributes(node));
} permsSection.getAppendedNode().setValue(ent);
if (node.getExpiry() != 0L) {
attributes.getNode("expiry").setValue(node.getExpiry());
}
if (!node.getContexts().isEmpty()) {
attributes.getNode("context").setValue(serializeContextSet(node.getContexts()));
}
ConfigurationNode perm = SimpleConfigurationNode.root();
perm.getNode(node.getPermission()).setValue(attributes);
arr.getAppendedNode().setValue(perm);
} }
to.getNode("permissions").setValue(arr); to.getNode("permissions").setValue(permsSection);
} to.getNode("parents").setValue(parentsSection);
private static ConfigurationNode serializeContextSet(ContextSet contextSet) {
ConfigurationNode data = SimpleConfigurationNode.root();
Map<String, Collection<String>> map = contextSet.toMultimap().asMap();
map.forEach((k, v) -> {
List<String> values = new ArrayList<>(v);
int size = values.size();
if (size == 1) {
data.getNode(k).setValue(values.get(0));
} else if (size > 1) {
data.getNode(k).setValue(values);
}
});
return data;
}
private static MutableContextSet deserializeContextSet(ConfigurationNode data) {
Preconditions.checkArgument(data.hasMapChildren());
Map<Object, ? extends ConfigurationNode> dataMap = data.getChildrenMap();
ImmutableSetMultimap.Builder<String, String> map = ImmutableSetMultimap.builder();
for (Map.Entry<Object, ? extends ConfigurationNode> e : dataMap.entrySet()) {
String k = e.getKey().toString();
ConfigurationNode v = e.getValue();
if (v.hasListChildren()) {
List<? extends ConfigurationNode> values = v.getChildrenList();
for (ConfigurationNode value : values) {
map.put(k, value.getString());
}
} else {
map.put(k, v.getString());
}
}
return MutableContextSet.fromMultimap(map.build());
} }
} }

View File

@ -35,9 +35,9 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
public class HOCONBacking extends ConfigurateBacking { public class HoconDao extends ConfigurateDao {
public HOCONBacking(LuckPermsPlugin plugin, String dataFolderName) { public HoconDao(LuckPermsPlugin plugin, String dataFolderName) {
super(plugin, "HOCON", ".conf", dataFolderName); super(plugin, "HOCON", ".conf", dataFolderName);
} }

View File

@ -35,9 +35,9 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
public class JSONBacking extends ConfigurateBacking { public class JsonDao extends ConfigurateDao {
public JSONBacking(LuckPermsPlugin plugin, String dataFolderName) { public JsonDao(LuckPermsPlugin plugin, String dataFolderName) {
super(plugin, "JSON", ".json", dataFolderName); super(plugin, "JSON", ".json", dataFolderName);
} }

View File

@ -37,9 +37,9 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
public class YAMLBacking extends ConfigurateBacking { public class YamlDao extends ConfigurateDao {
public YAMLBacking(LuckPermsPlugin plugin, String dataFolderName) { public YamlDao(LuckPermsPlugin plugin, String dataFolderName) {
super(plugin, "YAML", ".yml", dataFolderName); super(plugin, "YAML", ".yml", dataFolderName);
} }

View File

@ -34,10 +34,11 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.backing.file.JSONBacking; import me.lucko.luckperms.common.storage.backing.file.JsonDao;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@ -53,23 +54,21 @@ import java.util.stream.Collectors;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@RequiredArgsConstructor @RequiredArgsConstructor
public class LegacyJSONSchemaMigration implements Runnable { public class LegacyJsonMigration implements Runnable {
private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
private final LuckPermsPlugin plugin; private final LuckPermsPlugin plugin;
private final JSONBacking backing; private final JsonDao backing;
private final File oldDataFolder; private final File oldDataFolder;
private final File newDataFolder; private final File newDataFolder;
private boolean writeElementToFile(File file, JsonElement element) { private void writeElementToFile(File file, JsonElement element) {
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) { try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
gson.toJson(element, writer); gson.toJson(element, writer);
writer.flush(); writer.flush();
return true;
} catch (Throwable t) { } catch (Throwable t) {
plugin.getLog().warn("Exception whilst writing to file: " + file.getAbsolutePath()); plugin.getLog().warn("Exception whilst writing to file: " + file.getAbsolutePath());
t.printStackTrace(); t.printStackTrace();
return false;
} }
} }
@ -213,7 +212,7 @@ public class LegacyJSONSchemaMigration implements Runnable {
for (NodeModel node : nodes) { for (NodeModel node : nodes) {
// just a raw, default node. // just a raw, default node.
boolean single = node.isValue() && boolean single = node.getValue() &&
node.getServer().equalsIgnoreCase("global") && node.getServer().equalsIgnoreCase("global") &&
node.getWorld().equalsIgnoreCase("global") && node.getWorld().equalsIgnoreCase("global") &&
node.getExpiry() == 0L && node.getExpiry() == 0L &&
@ -226,7 +225,7 @@ public class LegacyJSONSchemaMigration implements Runnable {
} }
JsonObject attributes = new JsonObject(); JsonObject attributes = new JsonObject();
attributes.addProperty("value", node.isValue()); attributes.addProperty("value", node.getValue());
if (!node.getServer().equals("global")) { if (!node.getServer().equals("global")) {
attributes.addProperty("server", node.getServer()); attributes.addProperty("server", node.getServer());
@ -241,7 +240,7 @@ public class LegacyJSONSchemaMigration implements Runnable {
} }
if (!node.getContexts().isEmpty()) { if (!node.getContexts().isEmpty()) {
attributes.add("context", node.getContextsAsJson()); attributes.add("context", ContextSetJsonSerializer.serializeContextSet(node.getContexts()));
} }
JsonObject perm = new JsonObject(); JsonObject perm = new JsonObject();

View File

@ -30,9 +30,10 @@ import lombok.RequiredArgsConstructor;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.storage.backing.sql.SQLBacking; import me.lucko.luckperms.common.storage.backing.sql.SqlDao;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.sql.Connection; import java.sql.Connection;
@ -50,9 +51,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class LegacySQLSchemaMigration implements Runnable { public class LegacySqlMigration implements Runnable {
private static final Type NODE_MAP_TYPE = new TypeToken<Map<String, Boolean>>() {}.getType(); private static final Type NODE_MAP_TYPE = new TypeToken<Map<String, Boolean>>() {}.getType();
private final SQLBacking backing; private final SqlDao backing;
@Override @Override
public void run() { public void run() {
@ -162,11 +163,11 @@ public class LegacySQLSchemaMigration implements Runnable {
for (NodeModel nd : nodes) { for (NodeModel nd : nodes) {
ps.setString(1, uuid.toString()); ps.setString(1, uuid.toString());
ps.setString(2, nd.getPermission()); ps.setString(2, nd.getPermission());
ps.setBoolean(3, nd.isValue()); ps.setBoolean(3, nd.getValue());
ps.setString(4, nd.getServer()); ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld()); ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry()); ps.setLong(6, nd.getExpiry());
ps.setString(7, nd.serializeContext()); ps.setString(7, backing.getGson().toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.addBatch(); ps.addBatch();
} }
ps.executeBatch(); ps.executeBatch();
@ -241,11 +242,11 @@ public class LegacySQLSchemaMigration implements Runnable {
for (NodeModel nd : nodes) { for (NodeModel nd : nodes) {
ps.setString(1, name); ps.setString(1, name);
ps.setString(2, nd.getPermission()); ps.setString(2, nd.getPermission());
ps.setBoolean(3, nd.isValue()); ps.setBoolean(3, nd.getValue());
ps.setString(4, nd.getServer()); ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld()); ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry()); ps.setLong(6, nd.getExpiry());
ps.setString(7, nd.serializeContext()); ps.setString(7, backing.getGson().toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.addBatch(); ps.addBatch();
} }
ps.executeBatch(); ps.executeBatch();

View File

@ -30,7 +30,7 @@ import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.backing.file.YAMLBacking; import me.lucko.luckperms.common.storage.backing.file.YamlDao;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
@ -53,12 +53,14 @@ import java.util.stream.Collectors;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@RequiredArgsConstructor @RequiredArgsConstructor
public class LegacyYAMLSchemaMigration implements Runnable { public class LegacyYamlMigration implements Runnable {
private final LuckPermsPlugin plugin; private final LuckPermsPlugin plugin;
private final YAMLBacking backing; private final YamlDao backing;
private final File oldDataFolder; private final File oldDataFolder;
private final File newDataFolder; private final File newDataFolder;
private final Yaml yaml = getYaml();
private static Yaml getYaml() { private static Yaml getYaml() {
DumperOptions options = new DumperOptions(); DumperOptions options = new DumperOptions();
options.setAllowUnicode(true); options.setAllowUnicode(true);
@ -66,21 +68,19 @@ public class LegacyYAMLSchemaMigration implements Runnable {
return new Yaml(options); return new Yaml(options);
} }
public boolean writeMapToFile(File file, Map<String, Object> values) { public void writeMapToFile(File file, Map<String, Object> values) {
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) { try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
getYaml().dump(values, writer); yaml.dump(values, writer);
writer.flush(); writer.flush();
return true;
} catch (Throwable t) { } catch (Throwable t) {
plugin.getLog().warn("Exception whilst writing to file: " + file.getAbsolutePath()); plugin.getLog().warn("Exception whilst writing to file: " + file.getAbsolutePath());
t.printStackTrace(); t.printStackTrace();
return false;
} }
} }
public Map<String, Object> readMapFromFile(File file) { public Map<String, Object> readMapFromFile(File file) {
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) { try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
return (Map<String, Object>) getYaml().load(reader); return (Map<String, Object>) yaml.load(reader);
} catch (Throwable t) { } catch (Throwable t) {
plugin.getLog().warn("Exception whilst reading from file: " + file.getAbsolutePath()); plugin.getLog().warn("Exception whilst reading from file: " + file.getAbsolutePath());
t.printStackTrace(); t.printStackTrace();
@ -211,7 +211,7 @@ public class LegacyYAMLSchemaMigration implements Runnable {
for (NodeModel node : nodes) { for (NodeModel node : nodes) {
// just a raw, default node. // just a raw, default node.
boolean single = node.isValue() && boolean single = node.getValue() &&
node.getServer().equalsIgnoreCase("global") && node.getServer().equalsIgnoreCase("global") &&
node.getWorld().equalsIgnoreCase("global") && node.getWorld().equalsIgnoreCase("global") &&
node.getExpiry() == 0L && node.getExpiry() == 0L &&
@ -228,7 +228,7 @@ public class LegacyYAMLSchemaMigration implements Runnable {
// create a map of node attributes // create a map of node attributes
Map<String, Object> attributes = new LinkedHashMap<>(); Map<String, Object> attributes = new LinkedHashMap<>();
attributes.put("value", node.isValue()); attributes.put("value", node.getValue());
if (!node.getServer().equals("global")) { if (!node.getServer().equals("global")) {
attributes.put("server", node.getServer()); attributes.put("server", node.getServer());

View File

@ -53,7 +53,7 @@ import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.UserIdentifier; import me.lucko.luckperms.common.references.UserIdentifier;
import me.lucko.luckperms.common.storage.DatastoreConfiguration; import me.lucko.luckperms.common.storage.DatastoreConfiguration;
import me.lucko.luckperms.common.storage.backing.AbstractBacking; import me.lucko.luckperms.common.storage.backing.AbstractDao;
import org.bson.Document; import org.bson.Document;
@ -64,24 +64,14 @@ import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class MongoDBBacking extends AbstractBacking { public class MongoDao extends AbstractDao {
private static <T> T call(Callable<T> c, T def) {
try {
return c.call();
} catch (Exception e) {
e.printStackTrace();
return def;
}
}
private final DatastoreConfiguration configuration; private final DatastoreConfiguration configuration;
private MongoClient mongoClient; private MongoClient mongoClient;
@ -90,12 +80,18 @@ public class MongoDBBacking extends AbstractBacking {
@Getter @Getter
private final String prefix; private final String prefix;
public MongoDBBacking(LuckPermsPlugin plugin, DatastoreConfiguration configuration, String prefix) { public MongoDao(LuckPermsPlugin plugin, DatastoreConfiguration configuration, String prefix) {
super(plugin, "MongoDB"); super(plugin, "MongoDB");
this.configuration = configuration; this.configuration = configuration;
this.prefix = prefix; this.prefix = prefix;
} }
private boolean reportException(Exception ex) {
plugin.getLog().warn("Exception thrown whilst performing i/o: ");
ex.printStackTrace();
return false;
}
@Override @Override
public void init() { public void init() {
MongoCredential credential = null; MongoCredential credential = null;
@ -162,7 +158,7 @@ public class MongoDBBacking extends AbstractBacking {
@Override @Override
public boolean logAction(LogEntry entry) { public boolean logAction(LogEntry entry) {
return call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "action"); MongoCollection<Document> c = database.getCollection(prefix + "action");
//noinspection deprecation //noinspection deprecation
@ -179,14 +175,16 @@ public class MongoDBBacking extends AbstractBacking {
} }
c.insertOne(doc, new InsertOneOptions()); c.insertOne(doc, new InsertOneOptions());
return true; } catch (Exception e) {
}, false); return reportException(e);
}
return true;
} }
@Override @Override
public Log getLog() { public Log getLog() {
return call(() -> { Log.Builder log = Log.builder();
final Log.Builder log = Log.builder(); try {
MongoCollection<Document> c = database.getCollection(prefix + "action"); MongoCollection<Document> c = database.getCollection(prefix + "action");
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
@ -210,14 +208,16 @@ public class MongoDBBacking extends AbstractBacking {
log.add(e); log.add(e);
} }
} }
} catch (Exception e) {
return log.build(); reportException(e);
}, null); return null;
}
return log.build();
} }
@Override @Override
public boolean applyBulkUpdate(BulkUpdate bulkUpdate) { public boolean applyBulkUpdate(BulkUpdate bulkUpdate) {
return call(() -> { try {
if (bulkUpdate.getDataType().isIncludingUsers()) { if (bulkUpdate.getDataType().isIncludingUsers()) {
MongoCollection<Document> c = database.getCollection(prefix + "users"); MongoCollection<Document> c = database.getCollection(prefix + "users");
@ -234,20 +234,20 @@ public class MongoDBBacking extends AbstractBacking {
nodes.add(NodeModel.fromNode(node)); nodes.add(NodeModel.fromNode(node));
} }
Set<Node> results = nodes.stream() Set<NodeModel> results = nodes.stream()
.map(n -> Optional.ofNullable(bulkUpdate.apply(n))) .map(bulkUpdate::apply)
.filter(Optional::isPresent) .filter(Objects::nonNull)
.map(Optional::get)
.map(NodeModel::toNode)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Document permsDoc = new Document(); if (!nodes.equals(results)) {
for (Map.Entry<String, Boolean> e : convert(exportToLegacy(results)).entrySet()) { Document permsDoc = new Document();
permsDoc.append(e.getKey(), e.getValue()); for (Map.Entry<String, Boolean> e : convert(exportToLegacy(results.stream().map(NodeModel::toNode).collect(Collectors.toList()))).entrySet()) {
} permsDoc.append(e.getKey(), e.getValue());
}
d.put("perms", perms); d.put("perms", perms);
c.replaceOne(new Document("_id", uuid), d); c.replaceOne(new Document("_id", uuid), d);
}
} }
} }
} }
@ -268,26 +268,28 @@ public class MongoDBBacking extends AbstractBacking {
nodes.add(NodeModel.fromNode(node)); nodes.add(NodeModel.fromNode(node));
} }
Set<Node> results = nodes.stream() Set<NodeModel> results = nodes.stream()
.map(n -> Optional.ofNullable(bulkUpdate.apply(n))) .map(bulkUpdate::apply)
.filter(Optional::isPresent) .filter(Objects::nonNull)
.map(Optional::get)
.map(NodeModel::toNode)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Document permsDoc = new Document(); if (!nodes.equals(results)) {
for (Map.Entry<String, Boolean> e : convert(exportToLegacy(results)).entrySet()) { Document permsDoc = new Document();
permsDoc.append(e.getKey(), e.getValue()); for (Map.Entry<String, Boolean> e : convert(exportToLegacy(results.stream().map(NodeModel::toNode).collect(Collectors.toList()))).entrySet()) {
} permsDoc.append(e.getKey(), e.getValue());
}
d.put("perms", perms); d.put("perms", perms);
c.replaceOne(new Document("_id", holder), d); c.replaceOne(new Document("_id", holder), d);
}
} }
} }
} }
} catch (Exception e) {
return true; reportException(e);
}, false); return false;
}
return true;
} }
@Override @Override
@ -295,80 +297,73 @@ public class MongoDBBacking extends AbstractBacking {
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username)); User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
user.getIoLock().lock(); user.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "users");
MongoCollection<Document> c = database.getCollection(prefix + "users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (cursor.hasNext()) { if (cursor.hasNext()) {
// User exists, let's load. // User exists, let's load.
Document d = cursor.next(); Document d = cursor.next();
user.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream() user.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream()
.map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue())) .map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue()))
.collect(Collectors.toSet()) .collect(Collectors.toSet())
); );
user.getPrimaryGroup().setStoredValue(d.getString("primaryGroup")); user.getPrimaryGroup().setStoredValue(d.getString("primaryGroup"));
user.setName(name, true); user.setName(name, true);
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false); boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().isPresent() && (name == null || !user.getName().get().equalsIgnoreCase(name))) { if (user.getName().isPresent() && (name == null || !user.getName().get().equalsIgnoreCase(name))) {
save = true; save = true;
} }
if (save) { if (save) {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user)); c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
} }
} else { } else {
if (GenericUserManager.shouldSave(user)) { if (GenericUserManager.shouldSave(user)) {
user.clearNodes(); user.clearNodes();
user.getPrimaryGroup().setStoredValue(null); user.getPrimaryGroup().setStoredValue(null);
plugin.getUserManager().giveDefaultIfNeeded(user, false); plugin.getUserManager().giveDefaultIfNeeded(user, false);
}
} }
} }
return true; }
}, false); } catch (Exception e) {
return reportException(e);
} finally { } finally {
user.getIoLock().unlock(); user.getIoLock().unlock();
user.getRefreshBuffer().requestDirectly(); user.getRefreshBuffer().requestDirectly();
} }
return true;
} }
@Override @Override
public boolean saveUser(User user) { public boolean saveUser(User user) {
if (!GenericUserManager.shouldSave(user)) {
user.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection(prefix + "users");
return c.deleteOne(new Document("_id", user.getUuid())).wasAcknowledged();
}, false);
} finally {
user.getIoLock().unlock();
}
}
user.getIoLock().lock(); user.getIoLock().lock();
try { try {
return call(() -> { if (!GenericUserManager.shouldSave(user)) {
MongoCollection<Document> c = database.getCollection(prefix + "users"); MongoCollection<Document> c = database.getCollection(prefix + "users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) { return c.deleteOne(new Document("_id", user.getUuid())).wasAcknowledged();
if (!cursor.hasNext()) { }
c.insertOne(fromUser(user));
} else { MongoCollection<Document> c = database.getCollection(prefix + "users");
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user)); try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
} if (!cursor.hasNext()) {
c.insertOne(fromUser(user));
} else {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
} }
return true; }
}, false); } catch (Exception e) {
return reportException(e);
} finally { } finally {
user.getIoLock().unlock(); user.getIoLock().unlock();
} }
return true;
} }
@Override @Override
public Set<UUID> getUniqueUsers() { public Set<UUID> getUniqueUsers() {
Set<UUID> uuids = new HashSet<>(); Set<UUID> uuids = new HashSet<>();
boolean success = call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "users"); MongoCollection<Document> c = database.getCollection(prefix + "users");
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
@ -377,17 +372,16 @@ public class MongoDBBacking extends AbstractBacking {
uuids.add(d.get("_id", UUID.class)); uuids.add(d.get("_id", UUID.class));
} }
} }
} catch (Exception e) {
return true; return null;
}, false); }
return uuids;
return success ? uuids : null;
} }
@Override @Override
public List<HeldPermission<UUID>> getUsersWithPermission(String permission) { public List<HeldPermission<UUID>> getUsersWithPermission(String permission) {
ImmutableList.Builder<HeldPermission<UUID>> held = ImmutableList.builder(); ImmutableList.Builder<HeldPermission<UUID>> held = ImmutableList.builder();
boolean success = call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "users"); MongoCollection<Document> c = database.getCollection(prefix + "users");
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
@ -407,10 +401,11 @@ public class MongoDBBacking extends AbstractBacking {
} }
} }
} }
return true; } catch (Exception e) {
}, false); reportException(e);
return null;
return success ? held.build() : null; }
return held.build();
} }
@Override @Override
@ -418,26 +413,26 @@ public class MongoDBBacking extends AbstractBacking {
Group group = plugin.getGroupManager().getOrMake(name); Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock(); group.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "groups");
MongoCollection<Document> c = database.getCollection(prefix + "groups");
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (cursor.hasNext()) { if (cursor.hasNext()) {
// Group exists, let's load. // Group exists, let's load.
Document d = cursor.next(); Document d = cursor.next();
group.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream() group.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream()
.map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue())) .map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue()))
.collect(Collectors.toSet()) .collect(Collectors.toSet())
); );
} else { } else {
c.insertOne(fromGroup(group)); c.insertOne(fromGroup(group));
}
} }
return true; }
}, false); } catch (Exception e) {
return reportException(e);
} finally { } finally {
group.getIoLock().unlock(); group.getIoLock().unlock();
} }
return true;
} }
@Override @Override
@ -445,22 +440,22 @@ public class MongoDBBacking extends AbstractBacking {
Group group = plugin.getGroupManager().getOrMake(name); Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock(); group.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "groups");
MongoCollection<Document> c = database.getCollection(prefix + "groups");
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (cursor.hasNext()) { if (cursor.hasNext()) {
Document d = cursor.next(); Document d = cursor.next();
group.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream() group.setEnduringNodes(revert((Map<String, Boolean>) d.get("perms")).entrySet().stream()
.map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue())) .map(e -> NodeFactory.fromSerializedNode(e.getKey(), e.getValue()))
.collect(Collectors.toSet()) .collect(Collectors.toSet())
); );
return true; return true;
}
return false;
} }
}, false); return false;
}
} catch (Exception e) {
return reportException(e);
} finally { } finally {
group.getIoLock().unlock(); group.getIoLock().unlock();
} }
@ -469,39 +464,36 @@ public class MongoDBBacking extends AbstractBacking {
@Override @Override
public boolean loadAllGroups() { public boolean loadAllGroups() {
List<String> groups = new ArrayList<>(); List<String> groups = new ArrayList<>();
boolean success = call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "groups"); MongoCollection<Document> c = database.getCollection(prefix + "groups");
boolean b = true;
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) { while (cursor.hasNext()) {
String name = cursor.next().getString("_id"); String name = cursor.next().getString("_id");
if (!loadGroup(name)) { loadGroup(name);
b = false;
}
groups.add(name); groups.add(name);
} }
} }
return b; } catch (Exception e) {
}, false); reportException(e);
return false;
if (success) {
GroupManager gm = plugin.getGroupManager();
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
} }
return success;
GroupManager gm = plugin.getGroupManager();
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
return true;
} }
@Override @Override
public boolean saveGroup(Group group) { public boolean saveGroup(Group group) {
group.getIoLock().lock(); group.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "groups");
MongoCollection<Document> c = database.getCollection(prefix + "groups"); return c.replaceOne(new Document("_id", group.getName()), fromGroup(group)).wasAcknowledged();
return c.replaceOne(new Document("_id", group.getName()), fromGroup(group)).wasAcknowledged(); } catch (Exception e) {
}, false); return reportException(e);
} finally { } finally {
group.getIoLock().unlock(); group.getIoLock().unlock();
} }
@ -510,24 +502,25 @@ public class MongoDBBacking extends AbstractBacking {
@Override @Override
public boolean deleteGroup(Group group) { public boolean deleteGroup(Group group) {
group.getIoLock().lock(); group.getIoLock().lock();
boolean success;
try { try {
success = call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "groups");
MongoCollection<Document> c = database.getCollection(prefix + "groups"); if (!c.deleteOne(new Document("_id", group.getName())).wasAcknowledged()) {
return c.deleteOne(new Document("_id", group.getName())).wasAcknowledged(); throw new RuntimeException();
}, false); }
} catch (Exception e) {
return reportException(e);
} finally { } finally {
group.getIoLock().unlock(); group.getIoLock().unlock();
} }
if (success) plugin.getGroupManager().unload(group); plugin.getGroupManager().unload(group);
return success; return true;
} }
@Override @Override
public List<HeldPermission<String>> getGroupsWithPermission(String permission) { public List<HeldPermission<String>> getGroupsWithPermission(String permission) {
ImmutableList.Builder<HeldPermission<String>> held = ImmutableList.builder(); ImmutableList.Builder<HeldPermission<String>> held = ImmutableList.builder();
boolean success = call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "groups"); MongoCollection<Document> c = database.getCollection(prefix + "groups");
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
@ -547,10 +540,11 @@ public class MongoDBBacking extends AbstractBacking {
} }
} }
} }
return true; } catch (Exception e) {
}, false); reportException(e);
return null;
return success ? held.build() : null; }
return held.build();
} }
@Override @Override
@ -558,22 +552,22 @@ public class MongoDBBacking extends AbstractBacking {
Track track = plugin.getTrackManager().getOrMake(name); Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock(); track.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "tracks");
MongoCollection<Document> c = database.getCollection(prefix + "tracks");
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
if (!cursor.hasNext()) { if (!cursor.hasNext()) {
c.insertOne(fromTrack(track)); c.insertOne(fromTrack(track));
} else { } else {
Document d = cursor.next(); Document d = cursor.next();
track.setGroups((List<String>) d.get("groups")); track.setGroups((List<String>) d.get("groups"));
}
} }
return true; }
}, false); } catch (Exception e) {
return reportException(e);
} finally { } finally {
track.getIoLock().unlock(); track.getIoLock().unlock();
} }
return true;
} }
@Override @Override
@ -581,18 +575,18 @@ public class MongoDBBacking extends AbstractBacking {
Track track = plugin.getTrackManager().getOrMake(name); Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock(); track.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "tracks");
MongoCollection<Document> c = database.getCollection(prefix + "tracks");
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
if (cursor.hasNext()) { if (cursor.hasNext()) {
Document d = cursor.next(); Document d = cursor.next();
track.setGroups((List<String>) d.get("groups")); track.setGroups((List<String>) d.get("groups"));
return true; return true;
}
return false;
} }
}, false); return false;
}
} catch (Exception e) {
return reportException(e);
} finally { } finally {
track.getIoLock().unlock(); track.getIoLock().unlock();
} }
@ -601,39 +595,36 @@ public class MongoDBBacking extends AbstractBacking {
@Override @Override
public boolean loadAllTracks() { public boolean loadAllTracks() {
List<String> tracks = new ArrayList<>(); List<String> tracks = new ArrayList<>();
boolean success = call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "tracks"); MongoCollection<Document> c = database.getCollection(prefix + "tracks");
boolean b = true;
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) { while (cursor.hasNext()) {
String name = cursor.next().getString("_id"); String name = cursor.next().getString("_id");
if (!loadTrack(name)) { loadTrack(name);
b = false;
}
tracks.add(name); tracks.add(name);
} }
} }
return b; } catch (Exception e) {
}, false); reportException(e);
return false;
if (success) {
TrackManager tm = plugin.getTrackManager();
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
} }
return success;
TrackManager tm = plugin.getTrackManager();
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
return true;
} }
@Override @Override
public boolean saveTrack(Track track) { public boolean saveTrack(Track track) {
track.getIoLock().lock(); track.getIoLock().lock();
try { try {
return call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "tracks");
MongoCollection<Document> c = database.getCollection(prefix + "tracks"); return c.replaceOne(new Document("_id", track.getName()), fromTrack(track)).wasAcknowledged();
return c.replaceOne(new Document("_id", track.getName()), fromTrack(track)).wasAcknowledged(); } catch (Exception e) {
}, false); return reportException(e);
} finally { } finally {
track.getIoLock().unlock(); track.getIoLock().unlock();
} }
@ -642,23 +633,24 @@ public class MongoDBBacking extends AbstractBacking {
@Override @Override
public boolean deleteTrack(Track track) { public boolean deleteTrack(Track track) {
track.getIoLock().lock(); track.getIoLock().lock();
boolean success;
try { try {
success = call(() -> { MongoCollection<Document> c = database.getCollection(prefix + "tracks");
MongoCollection<Document> c = database.getCollection(prefix + "tracks"); if (!c.deleteOne(new Document("_id", track.getName())).wasAcknowledged()) {
return c.deleteOne(new Document("_id", track.getName())).wasAcknowledged(); throw new RuntimeException();
}, false); }
} catch (Exception e) {
return reportException(e);
} finally { } finally {
track.getIoLock().unlock(); track.getIoLock().unlock();
} }
if (success) plugin.getTrackManager().unload(track); plugin.getTrackManager().unload(track);
return success; return true;
} }
@Override @Override
public boolean saveUUIDData(UUID uuid, String username) { public boolean saveUUIDData(UUID uuid, String username) {
return call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "uuid"); MongoCollection<Document> c = database.getCollection(prefix + "uuid");
try (MongoCursor<Document> cursor = c.find(new Document("_id", uuid)).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", uuid)).iterator()) {
@ -668,14 +660,15 @@ public class MongoDBBacking extends AbstractBacking {
c.insertOne(new Document("_id", uuid).append("name", username.toLowerCase())); c.insertOne(new Document("_id", uuid).append("name", username.toLowerCase()));
} }
} }
} catch (Exception e) {
return true; return reportException(e);
}, false); }
return true;
} }
@Override @Override
public UUID getUUID(String username) { public UUID getUUID(String username) {
return call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "uuid"); MongoCollection<Document> c = database.getCollection(prefix + "uuid");
try (MongoCursor<Document> cursor = c.find(new Document("name", username.toLowerCase())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("name", username.toLowerCase())).iterator()) {
@ -684,12 +677,15 @@ public class MongoDBBacking extends AbstractBacking {
} }
} }
return null; return null;
}, null); } catch (Exception e) {
reportException(e);
return null;
}
} }
@Override @Override
public String getName(UUID uuid) { public String getName(UUID uuid) {
return call(() -> { try {
MongoCollection<Document> c = database.getCollection(prefix + "uuid"); MongoCollection<Document> c = database.getCollection(prefix + "uuid");
try (MongoCursor<Document> cursor = c.find(new Document("_id", uuid)).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", uuid)).iterator()) {
@ -698,7 +694,10 @@ public class MongoDBBacking extends AbstractBacking {
} }
} }
return null; return null;
}, null); } catch (Exception e) {
reportException(e);
return null;
}
} }
/* MongoDB does not allow '.' or '$' in key names. /* MongoDB does not allow '.' or '$' in key names.

View File

@ -32,21 +32,17 @@ import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@AllArgsConstructor @AllArgsConstructor
public class WrappedConnection implements Connection { public class NonClosableConnection implements Connection {
@Delegate(excludes = Exclude.class) @Delegate(excludes = Exclude.class)
private Connection delegate; private Connection delegate;
private final boolean shouldClose;
@Override @Override
public void close() throws SQLException { public void close() throws SQLException {
if (shouldClose) {
delegate.close();
}
} }
private interface Exclude { private interface Exclude {
void close(); void close() throws SQLException;
} }
} }

View File

@ -30,6 +30,7 @@ import lombok.Getter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.HeldPermission;
@ -37,6 +38,7 @@ import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate; import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.managers.GenericUserManager; import me.lucko.luckperms.common.managers.GenericUserManager;
import me.lucko.luckperms.common.managers.GroupManager; import me.lucko.luckperms.common.managers.GroupManager;
import me.lucko.luckperms.common.managers.TrackManager; import me.lucko.luckperms.common.managers.TrackManager;
@ -47,9 +49,9 @@ import me.lucko.luckperms.common.node.NodeHeldPermission;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.UserIdentifier; import me.lucko.luckperms.common.references.UserIdentifier;
import me.lucko.luckperms.common.storage.backing.AbstractBacking; import me.lucko.luckperms.common.storage.backing.AbstractDao;
import me.lucko.luckperms.common.storage.backing.legacy.LegacySQLSchemaMigration; import me.lucko.luckperms.common.storage.backing.legacy.LegacySqlMigration;
import me.lucko.luckperms.common.storage.backing.sql.provider.SQLProvider; import me.lucko.luckperms.common.storage.backing.sql.provider.AbstractConnectionFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
@ -72,7 +74,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SQLBacking extends AbstractBacking { public class SqlDao extends AbstractDao {
private static final Type LIST_STRING_TYPE = new TypeToken<List<String>>(){}.getType(); private static final Type LIST_STRING_TYPE = new TypeToken<List<String>>(){}.getType();
private static final String USER_PERMISSIONS_SELECT = "SELECT permission, value, server, world, expiry, contexts FROM {prefix}user_permissions WHERE uuid=?"; private static final String USER_PERMISSIONS_SELECT = "SELECT permission, value, server, world, expiry, contexts FROM {prefix}user_permissions WHERE uuid=?";
@ -118,12 +120,12 @@ public class SQLBacking extends AbstractBacking {
private final Gson gson; private final Gson gson;
@Getter @Getter
private final SQLProvider provider; private final AbstractConnectionFactory provider;
@Getter @Getter
private final Function<String, String> prefix; private final Function<String, String> prefix;
public SQLBacking(LuckPermsPlugin plugin, SQLProvider provider, String prefix) { public SqlDao(LuckPermsPlugin plugin, AbstractConnectionFactory provider, String prefix) {
super(plugin, provider.getName()); super(plugin, provider.getName());
this.provider = provider; this.provider = provider;
this.prefix = s -> s.replace("{prefix}", prefix); this.prefix = s -> s.replace("{prefix}", prefix);
@ -189,7 +191,7 @@ public class SQLBacking extends AbstractBacking {
plugin.getLog().severe("Starting migration from legacy schema. This could take a while...."); plugin.getLog().severe("Starting migration from legacy schema. This could take a while....");
plugin.getLog().severe("Please do not stop your server while the migration takes place."); plugin.getLog().severe("Please do not stop your server while the migration takes place.");
new LegacySQLSchemaMigration(this).run(); new LegacySqlMigration(this).run();
} }
} }
@ -322,7 +324,7 @@ public class SQLBacking extends AbstractBacking {
String world = rs.getString("world"); String world = rs.getString("world");
long expiry = rs.getLong("expiry"); long expiry = rs.getLong("expiry");
String contexts = rs.getString("contexts"); String contexts = rs.getString("contexts");
data.add(NodeModel.deserialize(permission, value, server, world, expiry, contexts)); data.add(deserializeNode(permission, value, server, world, expiry, contexts));
} }
} }
} }
@ -422,7 +424,7 @@ public class SQLBacking extends AbstractBacking {
String world = rs.getString("world"); String world = rs.getString("world");
long expiry = rs.getLong("expiry"); long expiry = rs.getLong("expiry");
String contexts = rs.getString("contexts"); String contexts = rs.getString("contexts");
remote.add(NodeModel.deserialize(permission, value, server, world, expiry, contexts)); remote.add(deserializeNode(permission, value, server, world, expiry, contexts));
} }
} }
} }
@ -443,11 +445,11 @@ public class SQLBacking extends AbstractBacking {
for (NodeModel nd : toRemove) { for (NodeModel nd : toRemove) {
ps.setString(1, user.getUuid().toString()); ps.setString(1, user.getUuid().toString());
ps.setString(2, nd.getPermission()); ps.setString(2, nd.getPermission());
ps.setBoolean(3, nd.isValue()); ps.setBoolean(3, nd.getValue());
ps.setString(4, nd.getServer()); ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld()); ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry()); ps.setLong(6, nd.getExpiry());
ps.setString(7, nd.serializeContext()); ps.setString(7, gson.toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.addBatch(); ps.addBatch();
} }
ps.executeBatch(); ps.executeBatch();
@ -464,11 +466,11 @@ public class SQLBacking extends AbstractBacking {
for (NodeModel nd : toAdd) { for (NodeModel nd : toAdd) {
ps.setString(1, user.getUuid().toString()); ps.setString(1, user.getUuid().toString());
ps.setString(2, nd.getPermission()); ps.setString(2, nd.getPermission());
ps.setBoolean(3, nd.isValue()); ps.setBoolean(3, nd.getValue());
ps.setString(4, nd.getServer()); ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld()); ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry()); ps.setLong(6, nd.getExpiry());
ps.setString(7, nd.serializeContext()); ps.setString(7, gson.toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.addBatch(); ps.addBatch();
} }
ps.executeBatch(); ps.executeBatch();
@ -551,7 +553,7 @@ public class SQLBacking extends AbstractBacking {
long expiry = rs.getLong("expiry"); long expiry = rs.getLong("expiry");
String contexts = rs.getString("contexts"); String contexts = rs.getString("contexts");
NodeModel data = NodeModel.deserialize(permission, value, server, world, expiry, contexts); NodeModel data = deserializeNode(permission, value, server, world, expiry, contexts);
held.add(NodeHeldPermission.of(holder, data)); held.add(NodeHeldPermission.of(holder, data));
} }
} }
@ -633,7 +635,7 @@ public class SQLBacking extends AbstractBacking {
String world = rs.getString("world"); String world = rs.getString("world");
long expiry = rs.getLong("expiry"); long expiry = rs.getLong("expiry");
String contexts = rs.getString("contexts"); String contexts = rs.getString("contexts");
data.add(NodeModel.deserialize(permission, value, server, world, expiry, contexts)); data.add(deserializeNode(permission, value, server, world, expiry, contexts));
} }
} }
} }
@ -720,7 +722,7 @@ public class SQLBacking extends AbstractBacking {
String world = rs.getString("world"); String world = rs.getString("world");
long expiry = rs.getLong("expiry"); long expiry = rs.getLong("expiry");
String contexts = rs.getString("contexts"); String contexts = rs.getString("contexts");
remote.add(NodeModel.deserialize(permission, value, server, world, expiry, contexts)); remote.add(deserializeNode(permission, value, server, world, expiry, contexts));
} }
} }
} }
@ -742,11 +744,11 @@ public class SQLBacking extends AbstractBacking {
for (NodeModel nd : toRemove) { for (NodeModel nd : toRemove) {
ps.setString(1, group.getName()); ps.setString(1, group.getName());
ps.setString(2, nd.getPermission()); ps.setString(2, nd.getPermission());
ps.setBoolean(3, nd.isValue()); ps.setBoolean(3, nd.getValue());
ps.setString(4, nd.getServer()); ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld()); ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry()); ps.setLong(6, nd.getExpiry());
ps.setString(7, nd.serializeContext()); ps.setString(7, gson.toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.addBatch(); ps.addBatch();
} }
ps.executeBatch(); ps.executeBatch();
@ -763,11 +765,11 @@ public class SQLBacking extends AbstractBacking {
for (NodeModel nd : toAdd) { for (NodeModel nd : toAdd) {
ps.setString(1, group.getName()); ps.setString(1, group.getName());
ps.setString(2, nd.getPermission()); ps.setString(2, nd.getPermission());
ps.setBoolean(3, nd.isValue()); ps.setBoolean(3, nd.getValue());
ps.setString(4, nd.getServer()); ps.setString(4, nd.getServer());
ps.setString(5, nd.getWorld()); ps.setString(5, nd.getWorld());
ps.setLong(6, nd.getExpiry()); ps.setLong(6, nd.getExpiry());
ps.setString(7, nd.serializeContext()); ps.setString(7, gson.toJson(ContextSetJsonSerializer.serializeContextSet(nd.getContexts())));
ps.addBatch(); ps.addBatch();
} }
ps.executeBatch(); ps.executeBatch();
@ -825,7 +827,7 @@ public class SQLBacking extends AbstractBacking {
long expiry = rs.getLong("expiry"); long expiry = rs.getLong("expiry");
String contexts = rs.getString("contexts"); String contexts = rs.getString("contexts");
NodeModel data = NodeModel.deserialize(permission, value, server, world, expiry, contexts); NodeModel data = deserializeNode(permission, value, server, world, expiry, contexts);
held.add(NodeHeldPermission.of(holder, data)); held.add(NodeHeldPermission.of(holder, data));
} }
} }
@ -1113,4 +1115,9 @@ public class SQLBacking extends AbstractBacking {
return Maps.immutableEntry(toAdd, toRemove); return Maps.immutableEntry(toAdd, toRemove);
} }
private NodeModel deserializeNode(String permission, boolean value, String server, String world, long expiry, String contexts) {
JsonObject context = gson.fromJson(contexts, JsonObject.class);
return NodeModel.of(permission, value, server, world, expiry, ContextSetJsonSerializer.deserializeContextSet(context).makeImmutable());
}
} }

View File

@ -28,14 +28,13 @@ package me.lucko.luckperms.common.storage.backing.sql.provider;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.common.storage.backing.sql.WrappedConnection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class SQLProvider { public abstract class AbstractConnectionFactory {
@Getter @Getter
private final String name; private final String name;
@ -48,6 +47,6 @@ public abstract class SQLProvider {
return Collections.emptyMap(); return Collections.emptyMap();
} }
public abstract WrappedConnection getConnection() throws SQLException; public abstract Connection getConnection() throws SQLException;
} }

View File

@ -23,9 +23,10 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.storage.backing.sql.provider; package me.lucko.luckperms.common.storage.backing.sql.provider.file;
import me.lucko.luckperms.common.storage.backing.sql.WrappedConnection; import me.lucko.luckperms.common.storage.backing.sql.NonClosableConnection;
import me.lucko.luckperms.common.storage.backing.sql.provider.AbstractConnectionFactory;
import java.io.File; import java.io.File;
import java.sql.Connection; import java.sql.Connection;
@ -34,14 +35,14 @@ import java.sql.SQLException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
abstract class FlatfileProvider extends SQLProvider { abstract class FlatfileConnectionFactory extends AbstractConnectionFactory {
protected static final DecimalFormat DF = new DecimalFormat("#.00"); protected static final DecimalFormat DF = new DecimalFormat("#.00");
protected final File file; protected final File file;
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock lock = new ReentrantLock();
private WrappedConnection connection; private Connection connection;
FlatfileProvider(String name, File file) { FlatfileConnectionFactory(String name, File file) {
super(name); super(name);
this.file = file; this.file = file;
} }
@ -62,7 +63,7 @@ abstract class FlatfileProvider extends SQLProvider {
} }
@Override @Override
public WrappedConnection getConnection() throws SQLException { public Connection getConnection() throws SQLException {
lock.lock(); lock.lock();
try { try {
if (this.connection == null || this.connection.isClosed()) { if (this.connection == null || this.connection.isClosed()) {
@ -72,7 +73,7 @@ abstract class FlatfileProvider extends SQLProvider {
Connection connection = DriverManager.getConnection(getDriverId() + ":" + file.getAbsolutePath()); Connection connection = DriverManager.getConnection(getDriverId() + ":" + file.getAbsolutePath());
if (connection != null) { if (connection != null) {
this.connection = new WrappedConnection(connection, false); this.connection = new NonClosableConnection(connection);
} }
} }
@ -81,7 +82,7 @@ abstract class FlatfileProvider extends SQLProvider {
} }
if (this.connection == null) { if (this.connection == null) {
throw new SQLException("Connection is null"); throw new SQLException("Unable to get a connection.");
} }
return this.connection; return this.connection;

View File

@ -23,14 +23,14 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.storage.backing.sql.provider; package me.lucko.luckperms.common.storage.backing.sql.provider.file;
import java.io.File; import java.io.File;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class H2Provider extends FlatfileProvider { public class H2ConnectionFactory extends FlatfileConnectionFactory {
public H2Provider(File file) { public H2ConnectionFactory(File file) {
super("H2", file); super("H2", file);
// backwards compat // backwards compat
@ -46,7 +46,8 @@ public class H2Provider extends FlatfileProvider {
File databaseFile = new File(super.file.getParent(), "luckperms-h2.mv.db"); File databaseFile = new File(super.file.getParent(), "luckperms-h2.mv.db");
if (databaseFile.exists()) { if (databaseFile.exists()) {
ret.put("File Size", DF.format(databaseFile.length() / 1048576) + "MB"); double size = databaseFile.length() / 1048576;
ret.put("File Size", DF.format(size) + "MB");
} else { } else {
ret.put("File Size", "0MB"); ret.put("File Size", "0MB");
} }

View File

@ -23,14 +23,14 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.storage.backing.sql.provider; package me.lucko.luckperms.common.storage.backing.sql.provider.file;
import java.io.File; import java.io.File;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class SQLiteProvider extends FlatfileProvider { public class SQLiteConnectionFactory extends FlatfileConnectionFactory {
public SQLiteProvider(File file) { public SQLiteConnectionFactory(File file) {
super("SQLite", file); super("SQLite", file);
// backwards compat // backwards compat
@ -46,7 +46,8 @@ public class SQLiteProvider extends FlatfileProvider {
File databaseFile = new File(super.file.getParent(), "luckperms-sqlite.db"); File databaseFile = new File(super.file.getParent(), "luckperms-sqlite.db");
if (databaseFile.exists()) { if (databaseFile.exists()) {
ret.put("File Size", DF.format(databaseFile.length() / 1048576) + "MB"); double size = databaseFile.length() / 1048576;
ret.put("File Size", DF.format(size) + "MB");
} else { } else {
ret.put("File Size", "0MB"); ret.put("File Size", "0MB");
} }

View File

@ -23,13 +23,13 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.storage.backing.sql.provider; package me.lucko.luckperms.common.storage.backing.sql.provider.remote;
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import me.lucko.luckperms.common.storage.DatastoreConfiguration; import me.lucko.luckperms.common.storage.DatastoreConfiguration;
import me.lucko.luckperms.common.storage.backing.sql.WrappedConnection; import me.lucko.luckperms.common.storage.backing.sql.provider.AbstractConnectionFactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@ -38,13 +38,13 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class MySQLProvider extends SQLProvider { public class MySqlConnectionFactory extends AbstractConnectionFactory {
private final DatastoreConfiguration configuration; private final DatastoreConfiguration configuration;
private final String driverClass; private final String driverClass;
private HikariDataSource hikari; private HikariDataSource hikari;
public MySQLProvider(String name, String driverClass, DatastoreConfiguration configuration) { public MySqlConnectionFactory(String name, String driverClass, DatastoreConfiguration configuration) {
super(name); super(name);
this.configuration = configuration; this.configuration = configuration;
this.driverClass = driverClass; this.driverClass = driverClass;
@ -143,11 +143,11 @@ public class MySQLProvider extends SQLProvider {
} }
@Override @Override
public WrappedConnection getConnection() throws SQLException { public Connection getConnection() throws SQLException {
Connection connection = hikari.getConnection(); Connection connection = hikari.getConnection();
if (connection == null) { if (connection == null) {
throw new SQLException("Connection is null"); throw new SQLException("Unable to get a connection from the pool.");
} }
return new WrappedConnection(connection, true); return connection;
} }
} }

View File

@ -23,13 +23,13 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.storage.backing.sql.provider; package me.lucko.luckperms.common.storage.backing.sql.provider.remote;
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import me.lucko.luckperms.common.storage.DatastoreConfiguration; import me.lucko.luckperms.common.storage.DatastoreConfiguration;
import me.lucko.luckperms.common.storage.backing.sql.WrappedConnection; import me.lucko.luckperms.common.storage.backing.sql.provider.AbstractConnectionFactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@ -38,12 +38,12 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class PostgreSQLProvider extends SQLProvider { public class PostgreConnectionFactory extends AbstractConnectionFactory {
private final DatastoreConfiguration configuration; private final DatastoreConfiguration configuration;
private HikariDataSource hikari; private HikariDataSource hikari;
public PostgreSQLProvider(DatastoreConfiguration configuration) { public PostgreConnectionFactory(DatastoreConfiguration configuration) {
super("PostgreSQL"); super("PostgreSQL");
this.configuration = configuration; this.configuration = configuration;
} }
@ -117,11 +117,11 @@ public class PostgreSQLProvider extends SQLProvider {
} }
@Override @Override
public WrappedConnection getConnection() throws SQLException { public Connection getConnection() throws SQLException {
Connection connection = hikari.getConnection(); Connection connection = hikari.getConnection();
if (connection == null) { if (connection == null) {
throw new SQLException("Connection is null"); throw new SQLException("Unable to get a connection from the pool.");
} }
return new WrappedConnection(connection, true); return connection;
} }
} }

View File

@ -36,7 +36,7 @@ import com.google.gson.JsonObject;
import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.contexts.ContextSetComparator; import me.lucko.luckperms.common.contexts.ContextSetComparator;
import me.lucko.luckperms.common.node.NodeModel; import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer;
import me.lucko.luckperms.common.node.NodeWithContextComparator; import me.lucko.luckperms.common.node.NodeWithContextComparator;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData; import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.model.LPPermissionService; import me.lucko.luckperms.sponge.service.model.LPPermissionService;
@ -107,7 +107,7 @@ public class SubjectStorageModel {
JsonObject context = section.get("context").getAsJsonObject(); JsonObject context = section.get("context").getAsJsonObject();
JsonObject data = section.get("data").getAsJsonObject(); JsonObject data = section.get("data").getAsJsonObject();
ImmutableContextSet contextSet = NodeModel.deserializeContextSet(context).makeImmutable(); ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).makeImmutable();
ImmutableMap.Builder<String, Boolean> perms = ImmutableMap.builder(); ImmutableMap.Builder<String, Boolean> perms = ImmutableMap.builder();
for (Map.Entry<String, JsonElement> perm : data.entrySet()) { for (Map.Entry<String, JsonElement> perm : data.entrySet()) {
perms.put(perm.getKey(), perm.getValue().getAsBoolean()); perms.put(perm.getKey(), perm.getValue().getAsBoolean());
@ -130,7 +130,7 @@ public class SubjectStorageModel {
JsonObject context = section.get("context").getAsJsonObject(); JsonObject context = section.get("context").getAsJsonObject();
JsonObject data = section.get("data").getAsJsonObject(); JsonObject data = section.get("data").getAsJsonObject();
ImmutableContextSet contextSet = NodeModel.deserializeContextSet(context).makeImmutable(); ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).makeImmutable();
ImmutableMap.Builder<String, String> opts = ImmutableMap.builder(); ImmutableMap.Builder<String, String> opts = ImmutableMap.builder();
for (Map.Entry<String, JsonElement> opt : data.entrySet()) { for (Map.Entry<String, JsonElement> opt : data.entrySet()) {
opts.put(opt.getKey(), opt.getValue().getAsString()); opts.put(opt.getKey(), opt.getValue().getAsString());
@ -153,7 +153,7 @@ public class SubjectStorageModel {
JsonObject context = section.get("context").getAsJsonObject(); JsonObject context = section.get("context").getAsJsonObject();
JsonArray data = section.get("data").getAsJsonArray(); JsonArray data = section.get("data").getAsJsonArray();
ImmutableContextSet contextSet = NodeModel.deserializeContextSet(context).makeImmutable(); ImmutableContextSet contextSet = ContextSetJsonSerializer.deserializeContextSet(context).makeImmutable();
ImmutableList.Builder<SubjectReference> pars = ImmutableList.builder(); ImmutableList.Builder<SubjectReference> pars = ImmutableList.builder();
for (JsonElement p : data) { for (JsonElement p : data) {
if (!p.isJsonObject()) { if (!p.isJsonObject()) {
@ -189,7 +189,7 @@ public class SubjectStorageModel {
} }
JsonObject section = new JsonObject(); JsonObject section = new JsonObject();
section.add("context", NodeModel.serializeContextSet(e.getKey())); section.add("context", ContextSetJsonSerializer.serializeContextSet(e.getKey()));
JsonObject data = new JsonObject(); JsonObject data = new JsonObject();
@ -213,7 +213,7 @@ public class SubjectStorageModel {
} }
JsonObject section = new JsonObject(); JsonObject section = new JsonObject();
section.add("context", NodeModel.serializeContextSet(e.getKey())); section.add("context", ContextSetJsonSerializer.serializeContextSet(e.getKey()));
JsonObject data = new JsonObject(); JsonObject data = new JsonObject();
@ -237,7 +237,7 @@ public class SubjectStorageModel {
} }
JsonObject section = new JsonObject(); JsonObject section = new JsonObject();
section.add("context", NodeModel.serializeContextSet(e.getKey())); section.add("context", ContextSetJsonSerializer.serializeContextSet(e.getKey()));
JsonArray data = new JsonArray(); JsonArray data = new JsonArray();
for (SubjectReference ref : e.getValue()) { for (SubjectReference ref : e.getValue()) {