Java tutorial
/* * 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.actionlog; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.ToString; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import me.lucko.luckperms.api.LogEntry; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.utils.DateUtil; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; /** * An implementation of {@link LogEntry} and {@link LogEntry.Builder}, * with helper methods for populating and using the entry using internal * LuckPerms classes. */ @AllArgsConstructor(access = AccessLevel.PRIVATE) public class ExtendedLogEntry implements LogEntry { private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s"; /** * Compares two LogEntries * * @since 3.3 */ public static final Comparator<LogEntry> COMPARATOR = Comparator.comparingLong(LogEntry::getTimestamp) .thenComparing(LogEntry::getActor).thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER) .thenComparing(LogEntry::getType).thenComparing(e -> e.getActed().map(UUID::toString).orElse("")) .thenComparing(LogEntry::getActedName, String.CASE_INSENSITIVE_ORDER) .thenComparing(LogEntry::getAction); /** * Creates a new log entry builder * * @return a new builder */ public static ExtendedLogEntryBuilder build() { return new ExtendedLogEntryBuilder(); } private final long timestamp; private final UUID actor; private final String actorName; private final Type type; private final UUID acted; private final String actedName; private final String action; @Override public long getTimestamp() { return timestamp; } @Override public UUID getActor() { return actor; } @Override public String getActorName() { return actorName; } @Override public Type getType() { return type; } @Override public Optional<UUID> getActed() { return Optional.ofNullable(acted); } @Override public String getActedName() { return actedName; } @Override public String getAction() { return action; } @Override public int compareTo(LogEntry other) { Preconditions.checkNotNull(other, "other"); return COMPARATOR.compare(this, other); } public boolean matchesSearch(String query) { query = Preconditions.checkNotNull(query, "query").toLowerCase(); return actorName.toLowerCase().contains(query) || actedName.toLowerCase().contains(query) || action.toLowerCase().contains(query); } public String getFormatted() { return String.format(FORMAT, String.valueOf(actorName).equals("null") ? actor.toString() : actorName, Character.toString(type.getCode()), String.valueOf(actedName).equals("null") && acted != null ? acted.toString() : actedName, action); } public void submit(LuckPermsPlugin plugin, Sender sender) { plugin.getLogDispatcher().dispatch(this, sender); } @Override public String toString() { return "LogEntry(" + "timestamp=" + this.getTimestamp() + ", " + "actor=" + this.getActor() + ", " + "actorName=" + this.getActorName() + ", " + "type=" + this.getType() + ", " + "acted=" + this.getActed() + ", " + "actedName=" + this.getActedName() + ", " + "action=" + this.getAction() + ")"; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof LogEntry)) return false; final LogEntry other = (LogEntry) o; return this.getTimestamp() == other.getTimestamp() && this.getActor().equals(other.getActor()) && this.getActorName().equals(other.getActorName()) && this.getType() == other.getType() && this.getActed().equals(other.getActed()) && this.getActedName().equals(other.getActedName()) && this.getAction().equals(other.getAction()); } @Override public int hashCode() { final int PRIME = 59; int result = 1; result = result * PRIME + (int) (this.getTimestamp() >>> 32 ^ this.getTimestamp()); result = result * PRIME + this.getActor().hashCode(); result = result * PRIME + this.getActorName().hashCode(); result = result * PRIME + this.getType().hashCode(); result = result * PRIME + this.getActed().hashCode(); result = result * PRIME + this.getActedName().hashCode(); result = result * PRIME + this.getAction().hashCode(); return result; } @ToString public static class ExtendedLogEntryBuilder implements LogEntry.Builder { private long timestamp = 0L; private UUID actor = null; private String actorName = null; private Type type = null; private UUID acted = null; private String actedName = null; private String action = null; @Override public ExtendedLogEntryBuilder setTimestamp(long timestamp) { this.timestamp = timestamp; return this; } @Override public ExtendedLogEntryBuilder setActor(UUID actor) { this.actor = Preconditions.checkNotNull(actor, "actor"); return this; } @Override public ExtendedLogEntryBuilder setActorName(String actorName) { this.actorName = Preconditions.checkNotNull(actorName, "actorName"); return this; } @Override public ExtendedLogEntryBuilder setType(Type type) { this.type = Preconditions.checkNotNull(type, "type"); return this; } @Override public ExtendedLogEntryBuilder setActed(UUID acted) { this.acted = acted; // nullable return this; } @Override public ExtendedLogEntryBuilder setActedName(String actedName) { this.actedName = Preconditions.checkNotNull(actedName, "actedName"); return this; } @Override public ExtendedLogEntryBuilder setAction(String action) { this.action = Preconditions.checkNotNull(action, "action"); return this; } public ExtendedLogEntryBuilder timestamp(long timestamp) { return setTimestamp(timestamp); } public ExtendedLogEntryBuilder actor(UUID actor) { return setActor(actor); } public ExtendedLogEntryBuilder actorName(String actorName) { return setActorName(actorName); } public ExtendedLogEntryBuilder type(Type type) { return setType(type); } public ExtendedLogEntryBuilder acted(UUID acted) { return setActed(acted); } public ExtendedLogEntryBuilder actedName(String actedName) { return setActedName(actedName); } public ExtendedLogEntryBuilder action(String action) { return setAction(action); } public ExtendedLogEntryBuilder actor(Sender actor) { actorName(actor.getNameWithLocation()); actor(actor.getUuid()); return this; } public ExtendedLogEntryBuilder acted(PermissionHolder acted) { if (acted instanceof User) { actedName(((User) acted).getName().orElse("null")); acted(((User) acted).getUuid()); type(Type.USER); } else if (acted instanceof Group) { actedName(((Group) acted).getName()); type(Type.GROUP); } return this; } public ExtendedLogEntryBuilder acted(Track track) { actedName(track.getName()); type(Type.TRACK); return this; } public ExtendedLogEntryBuilder action(Object... args) { List<String> parts = new ArrayList<>(); for (Object o : args) { // special formatting for ContextSets instead of just #toString if (o instanceof ContextSet) { ContextSet set = (ContextSet) o; for (String value : set.getValues("server")) { parts.add("server=" + value); } for (String value : set.getValues("world")) { parts.add("world=" + value); } for (Map.Entry<String, String> context : set.toSet()) { if (context.getKey().equals("server") || context.getKey().equals("world")) { continue; } parts.add(context.getKey() + "=" + context.getValue()); } } else { parts.add(String.valueOf(o)); } } action(parts.stream().collect(Collectors.joining(" "))); return this; } @Override public ExtendedLogEntry build() { if (timestamp == 0L) { timestamp(DateUtil.unixSecondsNow()); } Preconditions.checkNotNull(actor, "actor"); Preconditions.checkNotNull(actorName, "actorName"); Preconditions.checkNotNull(type, "type"); Preconditions.checkNotNull(actedName, "actedName"); Preconditions.checkNotNull(action, "action"); return new ExtendedLogEntry(timestamp, actor, actorName, type, acted, actedName, action); } } public static JsonObject serializeWithId(UUID id, LogEntry entry) { JsonObject data = new JsonObject(); data.add("id", new JsonPrimitive(id.toString())); data.add("actor", new JsonPrimitive(entry.getActor().toString())); data.add("actorName", new JsonPrimitive(entry.getActorName())); data.add("type", new JsonPrimitive(entry.getType().name())); if (entry.getActed().isPresent()) { data.add("acted", new JsonPrimitive(entry.getActed().get().toString())); } data.add("actedName", new JsonPrimitive(entry.getActedName())); data.add("action", new JsonPrimitive(entry.getAction())); return data; } public static Map.Entry<UUID, ExtendedLogEntry> deserialize(JsonObject object) { ExtendedLogEntryBuilder builder = build(); UUID id = UUID.fromString(object.get("id").getAsString()); builder.actor(UUID.fromString(object.get("actor").getAsString())); builder.actorName(object.get("actorName").getAsString()); builder.type(Type.valueOf(object.get("type").getAsString())); if (object.has("acted")) { builder.actor(UUID.fromString(object.get("acted").getAsString())); } builder.actedName(object.get("actedName").getAsString()); builder.action(object.get("action").getAsString()); return Maps.immutableEntry(id, builder.build()); } }