Conflicts:
	pom.xml
This commit is contained in:
ljacqu
2017-01-29 14:44:35 +01:00
28 changed files with 878 additions and 356 deletions
+1 -25
View File
@@ -27,7 +27,6 @@ import fr.xephi.authme.permission.PermissionsSystemType;
import fr.xephi.authme.security.crypts.SHA256;
import fr.xephi.authme.service.BackupService;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.GeoIpService;
import fr.xephi.authme.service.MigrationService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
@@ -35,11 +34,9 @@ import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.CleanupTask;
import fr.xephi.authme.task.purge.PurgeService;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@@ -72,8 +69,6 @@ public class AuthMe extends JavaPlugin {
private DataSource database;
private BukkitService bukkitService;
private Injector injector;
private GeoIpService geoIpService;
private PlayerCache playerCache;
/**
* Constructor.
@@ -242,14 +237,13 @@ public class AuthMe extends JavaPlugin {
*/
protected void instantiateServices(Injector injector) {
// PlayerCache is still injected statically sometimes
playerCache = PlayerCache.getInstance();
PlayerCache playerCache = PlayerCache.getInstance();
injector.register(PlayerCache.class, playerCache);
database = injector.getSingleton(DataSource.class);
permsMan = injector.getSingleton(PermissionsManager.class);
bukkitService = injector.getSingleton(BukkitService.class);
commandHandler = injector.getSingleton(CommandHandler.class);
geoIpService = injector.getSingleton(GeoIpService.class);
// Trigger construction of API classes; they will keep track of the singleton
injector.getSingleton(NewAPI.class);
@@ -344,24 +338,6 @@ public class AuthMe extends JavaPlugin {
ConsoleLogger.close();
}
public String replaceAllInfo(String message, Player player) {
String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size());
String ipAddress = PlayerUtils.getPlayerIp(player);
Server server = getServer();
return message
.replace("&", "\u00a7")
.replace("{PLAYER}", player.getName())
.replace("{ONLINE}", playersOnline)
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
.replace("{IP}", ipAddress)
.replace("{LOGINS}", Integer.toString(playerCache.getLogged()))
.replace("{WORLD}", player.getWorld().getName())
.replace("{SERVER}", server.getServerName())
.replace("{VERSION}", server.getBukkitVersion())
// TODO: We should cache info like this, maybe with a class that extends Player?
.replace("{COUNTRY}", geoIpService.getCountryName(ipAddress));
}
/**
* Handle Bukkit commands.
*
@@ -1,8 +1,8 @@
package fr.xephi.authme.command;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -224,7 +224,7 @@ public class CommandDescription {
* @return The generated CommandDescription object
*/
public CommandDescription build() {
checkArgument(!CollectionUtils.isEmpty(labels), "Labels may not be empty");
checkArgument(!Utils.isCollectionEmpty(labels), "Labels may not be empty");
checkArgument(!StringUtils.isEmpty(description), "Description may not be empty");
checkArgument(!StringUtils.isEmpty(detailedDescription), "Detailed description may not be empty");
checkArgument(executableCommand != null, "Executable command must be set");
@@ -2,8 +2,8 @@ package fr.xephi.authme.command;
import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.command.CommandSender;
import javax.inject.Inject;
@@ -45,7 +45,7 @@ public class CommandMapper {
* @return The generated {@link FoundCommandResult}
*/
public FoundCommandResult mapPartsToCommand(CommandSender sender, final List<String> parts) {
if (CollectionUtils.isEmpty(parts)) {
if (Utils.isCollectionEmpty(parts)) {
return new FoundCommandResult(null, parts, null, 0.0, MISSING_BASE_COMMAND);
}
@@ -142,7 +142,7 @@ public class CommandMapper {
* @return A command if there was a complete match (including proper argument count), null otherwise
*/
private static CommandDescription getSuitableChild(CommandDescription baseCommand, List<String> parts) {
if (CollectionUtils.isEmpty(parts)) {
if (Utils.isCollectionEmpty(parts)) {
return null;
}
@@ -6,7 +6,7 @@ import de.luricos.bukkit.xAuth.xAuth;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginManager;
@@ -55,7 +55,7 @@ public class xAuthConverter implements Converter {
sender.sendMessage("[AuthMe] xAuth H2 database not found, checking for MySQL or SQLite data...");
}
List<Integer> players = getXAuthPlayers();
if (CollectionUtils.isEmpty(players)) {
if (Utils.isCollectionEmpty(players)) {
sender.sendMessage("[AuthMe] Error while importing xAuthPlayers: did not find any players");
return;
}
@@ -13,15 +13,16 @@ import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.BungeeService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.WelcomeMessageConfiguration;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
import java.util.List;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
@@ -54,6 +55,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject
private Settings settings;
@Inject
private WelcomeMessageConfiguration welcomeMessageConfiguration;
ProcessSyncPlayerLogin() {
}
@@ -103,15 +107,12 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
player.saveData();
// Login is done, display welcome message
List<String> welcomeMessage = welcomeMessageConfiguration.getWelcomeMessage(player);
if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
for (String s : settings.getWelcomeMessage()) {
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
}
welcomeMessage.forEach(bukkitService::broadcastMessage);
} else {
for (String s : settings.getWelcomeMessage()) {
player.sendMessage(plugin.replaceAllInfo(s, player));
}
welcomeMessage.forEach(player::sendMessage);
}
}
@@ -11,7 +11,6 @@ import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.command.CommandSender;
@@ -144,11 +143,11 @@ public class ValidationService implements Reloadable {
private boolean validateWhitelistAndBlacklist(String value, Property<List<String>> whitelist,
Property<List<String>> blacklist) {
List<String> whitelistValue = settings.getProperty(whitelist);
if (!CollectionUtils.isEmpty(whitelistValue)) {
if (!Utils.isCollectionEmpty(whitelistValue)) {
return containsIgnoreCase(whitelistValue, value);
}
List<String> blacklistValue = settings.getProperty(blacklist);
return CollectionUtils.isEmpty(blacklistValue) || !containsIgnoreCase(blacklistValue, value);
return Utils.isCollectionEmpty(blacklistValue) || !containsIgnoreCase(blacklistValue, value);
}
private static boolean containsIgnoreCase(Collection<String> coll, String needle) {
@@ -19,7 +19,6 @@ import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
public class Settings extends SettingsManager {
private final File pluginFolder;
private String[] welcomeMessage;
private String passwordEmailMessage;
private String recoveryCodeEmailMessage;
@@ -56,19 +55,9 @@ public class Settings extends SettingsManager {
return recoveryCodeEmailMessage;
}
/**
* Return the lines to output after an in-game registration.
*
* @return The welcome message
*/
public String[] getWelcomeMessage() {
return welcomeMessage;
}
private void loadSettingsFromFiles() {
passwordEmailMessage = readFile("email.html");
recoveryCodeEmailMessage = readFile("recovery_code_email.html");
welcomeMessage = readFile("welcome.txt").split("\\n");
}
@Override
@@ -0,0 +1,97 @@
package fr.xephi.authme.settings;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.GeoIpService;
import fr.xephi.authme.util.PlayerUtils;
import fr.xephi.authme.util.lazytags.Tag;
import fr.xephi.authme.util.lazytags.TagReplacer;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static fr.xephi.authme.util.FileUtils.copyFileFromResource;
import static fr.xephi.authme.util.lazytags.TagBuilder.createTag;
/**
* Configuration for the welcome message (welcome.txt).
*/
public class WelcomeMessageConfiguration implements Reloadable {
@DataFolder
@Inject
private File pluginFolder;
@Inject
private Server server;
@Inject
private GeoIpService geoIpService;
@Inject
private BukkitService bukkitService;
@Inject
private PlayerCache playerCache;
/** List of all supported tags for the welcome message. */
private final List<Tag<Player>> availableTags = Arrays.asList(
createTag("&", () -> "\u00a7"),
createTag("{PLAYER}", pl -> pl.getName()),
createTag("{ONLINE}", () -> Integer.toString(bukkitService.getOnlinePlayers().size())),
createTag("{MAXPLAYERS}", () -> Integer.toString(server.getMaxPlayers())),
createTag("{IP}", pl -> PlayerUtils.getPlayerIp(pl)),
createTag("{LOGINS}", () -> Integer.toString(playerCache.getLogged())),
createTag("{WORLD}", pl -> pl.getWorld().getName()),
createTag("{SERVER}", () -> server.getServerName()),
createTag("{VERSION}", () -> server.getBukkitVersion()),
createTag("{COUNTRY}", pl -> geoIpService.getCountryName(PlayerUtils.getPlayerIp(pl))));
private TagReplacer<Player> messageSupplier;
@PostConstruct
@Override
public void reload() {
List<String> welcomeMessage = readWelcomeFile();
messageSupplier = TagReplacer.newReplacer(availableTags, welcomeMessage);
}
/**
* Returns the welcome message for the given player.
*
* @param player the player for whom the welcome message should be prepared
* @return the welcome message
*/
public List<String> getWelcomeMessage(Player player) {
return messageSupplier.getAdaptedMessages(player);
}
/**
* @return the lines of the welcome message file
*/
private List<String> readWelcomeFile() {
File welcomeFile = new File(pluginFolder, "welcome.txt");
if (copyFileFromResource(welcomeFile, "welcome.txt")) {
try {
return Files.readAllLines(welcomeFile.toPath(), StandardCharsets.UTF_8);
} catch (IOException e) {
ConsoleLogger.logException("Failed to read welcome.txt file:", e);
}
} else {
ConsoleLogger.warning("Failed to copy welcome.txt from JAR");
}
return Collections.emptyList();
}
}
@@ -5,13 +5,21 @@ import ch.jalu.configme.resource.YamlFileResource;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.GeoIpService;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.PlayerUtils;
import fr.xephi.authme.util.lazytags.Tag;
import fr.xephi.authme.util.lazytags.WrappedTagReplacer;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static fr.xephi.authme.util.lazytags.TagBuilder.createTag;
/**
* Manages configurable commands to be run when various events occur.
*/
@@ -19,15 +27,20 @@ public class CommandManager implements Reloadable {
private final File dataFolder;
private final BukkitService bukkitService;
private final GeoIpService geoIpService;
private final CommandMigrationService commandMigrationService;
private final List<Tag<Player>> availableTags = buildAvailableTags();
private CommandConfig commandConfig;
private WrappedTagReplacer<Command, Player> onJoinCommands;
private WrappedTagReplacer<Command, Player> onLoginCommands;
private WrappedTagReplacer<Command, Player> onRegisterCommands;
@Inject
CommandManager(@DataFolder File dataFolder, BukkitService bukkitService,
CommandManager(@DataFolder File dataFolder, BukkitService bukkitService, GeoIpService geoIpService,
CommandMigrationService commandMigrationService) {
this.dataFolder = dataFolder;
this.bukkitService = bukkitService;
this.geoIpService = geoIpService;
this.commandMigrationService = commandMigrationService;
reload();
}
@@ -38,7 +51,7 @@ public class CommandManager implements Reloadable {
* @param player the joining player
*/
public void runCommandsOnJoin(Player player) {
executeCommands(player, commandConfig.getOnJoin());
executeCommands(player, onJoinCommands.getAdaptedItems(player));
}
/**
@@ -47,7 +60,7 @@ public class CommandManager implements Reloadable {
* @param player the player who has registered
*/
public void runCommandsOnRegister(Player player) {
executeCommands(player, commandConfig.getOnRegister());
executeCommands(player, onRegisterCommands.getAdaptedItems(player));
}
/**
@@ -56,11 +69,11 @@ public class CommandManager implements Reloadable {
* @param player the player that logged in
*/
public void runCommandsOnLogin(Player player) {
executeCommands(player, commandConfig.getOnLogin());
executeCommands(player, onLoginCommands.getAdaptedItems(player));
}
private void executeCommands(Player player, Map<String, Command> commands) {
for (Command command : commands.values()) {
private void executeCommands(Player player, List<Command> commands) {
for (Command command : commands) {
final String execution = command.getCommand().replace("%p", player.getName());
if (Executor.CONSOLE.equals(command.getExecutor())) {
bukkitService.dispatchConsoleCommand(execution);
@@ -77,8 +90,22 @@ public class CommandManager implements Reloadable {
SettingsManager settingsManager = new SettingsManager(
new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
onJoinCommands = newReplacer(commandConfig.getOnJoin());
onLoginCommands = newReplacer(commandConfig.getOnLogin());
onRegisterCommands = newReplacer(commandConfig.getOnRegister());
}
private WrappedTagReplacer<Command, Player> newReplacer(Map<String, Command> commands) {
return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand,
(cmd, text) -> new Command(text, cmd.getExecutor()));
}
private List<Tag<Player>> buildAvailableTags() {
return Arrays.asList(
createTag("%p", pl -> pl.getName()),
createTag("%nick", pl -> pl.getDisplayName()),
createTag("%ip", pl -> PlayerUtils.getPlayerIp(pl)),
createTag("%country", pl -> geoIpService.getCountryName(PlayerUtils.getPlayerIp(pl))));
}
}
@@ -3,10 +3,10 @@ package fr.xephi.authme.task.purge;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PurgeSettings;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
@@ -75,7 +75,7 @@ public class PurgeService {
public void runPurge(CommandSender sender, long until, boolean includeEntriesWithLastLoginZero) {
//todo: note this should may run async because it may executes a SQL-Query
Set<String> toPurge = dataSource.getRecordsToPurge(until, includeEntriesWithLastLoginZero);
if (CollectionUtils.isEmpty(toPurge)) {
if (Utils.isCollectionEmpty(toPurge)) {
logAndSendMessage(sender, "No players to purge");
return;
}
@@ -1,63 +0,0 @@
package fr.xephi.authme.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Utils class for collections.
*/
public final class CollectionUtils {
// Utility class
private CollectionUtils() {
}
/**
* Get a range from a list based on start and count parameters in a safe way.
*
* @param <T> element
* @param list The List
* @param start The start index
* @param count The number of elements to add
*
* @return The sublist consisting at most of {@code count} elements (less if the parameters
* exceed the size of the list)
*/
public static <T> List<T> getRange(List<T> list, int start, int count) {
if (start >= list.size() || count <= 0) {
return new ArrayList<>();
} else if (start < 0) {
start = 0;
}
int end = Math.min(list.size(), start + count);
return list.subList(start, end);
}
/**
* Get all elements from a list starting from the given index.
*
* @param <T> element
* @param list The List
* @param start The start index
*
* @return The sublist of all elements from index {@code start} and on; empty list
* if the start index exceeds the list's size
*/
public static <T> List<T> getRange(List<T> list, int start) {
if (start >= list.size()) {
return new ArrayList<>();
}
return getRange(list, start, list.size() - start);
}
/**
* Null-safe way to check whether a collection is empty or not.
*
* @param coll The collection to verify
* @return True if the collection is null or empty, false otherwise
*/
public static boolean isEmpty(Collection<?> coll) {
return coll == null || coll.isEmpty();
}
}
@@ -2,6 +2,7 @@ package fr.xephi.authme.util;
import fr.xephi.authme.ConsoleLogger;
import java.util.Collection;
import java.util.regex.Pattern;
/**
@@ -50,6 +51,16 @@ public final class Utils {
}
}
/**
* Null-safe way to check whether a collection is empty or not.
*
* @param coll The collection to verify
* @return True if the collection is null or empty, false otherwise
*/
public static boolean isCollectionEmpty(Collection<?> coll) {
return coll == null || coll.isEmpty();
}
/**
* Return the available core count of the JVM.
*
@@ -0,0 +1,35 @@
package fr.xephi.authme.util.lazytags;
import java.util.function.Function;
/**
* Replaceable tag whose value depends on an argument.
*
* @param <A> the argument type
*/
public class DependentTag<A> implements Tag<A> {
private final String name;
private final Function<A, String> replacementFunction;
/**
* Constructor.
*
* @param name the tag (placeholder) that will be replaced
* @param replacementFunction the function producing the replacement
*/
public DependentTag(String name, Function<A, String> replacementFunction) {
this.name = name;
this.replacementFunction = replacementFunction;
}
@Override
public String getName() {
return name;
}
@Override
public String getValue(A argument) {
return replacementFunction.apply(argument);
}
}
@@ -0,0 +1,29 @@
package fr.xephi.authme.util.lazytags;
import java.util.function.Supplier;
/**
* Tag to be replaced that does not depend on an argument.
*
* @param <A> type of the argument (not used in this implementation)
*/
public class SimpleTag<A> implements Tag<A> {
private final String name;
private final Supplier<String> replacementFunction;
public SimpleTag(String name, Supplier<String> replacementFunction) {
this.name = name;
this.replacementFunction = replacementFunction;
}
@Override
public String getName() {
return name;
}
@Override
public String getValue(A argument) {
return replacementFunction.get();
}
}
@@ -0,0 +1,22 @@
package fr.xephi.authme.util.lazytags;
/**
* Represents a tag in a text to be replaced with a value (which may depend on some argument).
*
* @param <A> argument type the replacement may depend on
*/
public interface Tag<A> {
/**
* @return the tag to replace
*/
String getName();
/**
* Returns the value to replace the tag with for the given argument.
*
* @param argument the argument to evaluate the replacement for
* @return the replacement
*/
String getValue(A argument);
}
@@ -0,0 +1,21 @@
package fr.xephi.authme.util.lazytags;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Utility class for creating tags.
*/
public final class TagBuilder {
private TagBuilder() {
}
public static <A> Tag<A> createTag(String name, Function<A, String> replacementFunction) {
return new DependentTag<>(name, replacementFunction);
}
public static <A> Tag<A> createTag(String name, Supplier<String> replacementFunction) {
return new SimpleTag<>(name, replacementFunction);
}
}
@@ -0,0 +1,102 @@
package fr.xephi.authme.util.lazytags;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Replaces tags lazily by first determining which tags are being used
* and only applying those replacements afterwards.
*
* @param <A> the argument type
*/
public class TagReplacer<A> {
private final List<Tag<A>> tags;
private final Collection<String> messages;
/**
* Private constructor. Use {@link #newReplacer(Collection, Collection)}.
*
* @param tags the tags that are being used in the messages
* @param messages the messages
*/
private TagReplacer(List<Tag<A>> tags, Collection<String> messages) {
this.tags = tags;
this.messages = messages;
}
/**
* Creates a new instance of this class, which will provide the given
* messages adapted with the provided tags.
*
* @param allTags all available tags
* @param messages the messages to use
* @param <A> the argument type
* @return new tag replacer instance
*/
public static <A> TagReplacer<A> newReplacer(Collection<Tag<A>> allTags, Collection<String> messages) {
List<Tag<A>> usedTags = determineUsedTags(allTags, messages);
return new TagReplacer<>(usedTags, messages);
}
/**
* Returns the messages with the tags applied for the given argument.
*
* @param argument the argument to get the messages for
* @return the adapted messages
*/
public List<String> getAdaptedMessages(A argument) {
// Note ljacqu 20170121: Using a Map might seem more natural here but we avoid doing so for performance
// Although the performance gain here is probably minimal...
List<TagValue> tagValues = new LinkedList<>();
for (Tag<A> tag : tags) {
tagValues.add(new TagValue(tag.getName(), tag.getValue(argument)));
}
List<String> adaptedMessages = new LinkedList<>();
for (String line : messages) {
String adaptedLine = line;
for (TagValue tagValue : tagValues) {
adaptedLine = adaptedLine.replace(tagValue.tag, tagValue.value);
}
adaptedMessages.add(adaptedLine);
}
return adaptedMessages;
}
/**
* Determines which tags are used somewhere in the given list of messages.
*
* @param allTags all available tags
* @param messages the messages
* @param <A> argument type
* @return tags used at least once
*/
private static <A> List<Tag<A>> determineUsedTags(Collection<Tag<A>> allTags, Collection<String> messages) {
return allTags.stream()
.filter(tag -> messages.stream().anyMatch(msg -> msg.contains(tag.getName())))
.collect(Collectors.toList());
}
/** (Tag, value) pair. */
private static final class TagValue {
/** The tag to replace. */
private final String tag;
/** The value to replace with. */
private final String value;
TagValue(String tag, String value) {
this.tag = tag;
this.value = value;
}
@Override
public String toString() {
return "TagValue[tag='" + tag + "', value='" + value + "']";
}
}
}
@@ -0,0 +1,61 @@
package fr.xephi.authme.util.lazytags;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Applies tags lazily to the String property of an item. This class wraps
* a {@link TagReplacer} with the extraction of the String property and
* the creation of new items with the adapted string property.
*
* @param <T> the item type
* @param <A> the argument type to evaluate the replacements
*/
public class WrappedTagReplacer<T, A> {
private final Collection<T> items;
private final BiFunction<T, String, ? extends T> itemCreator;
private final TagReplacer<A> tagReplacer;
/**
* Constructor.
*
* @param allTags all available tags
* @param items the items to apply the replacements on
* @param stringGetter getter of the String property to adapt on the items
* @param itemCreator a function of signature (T, String) -> T: the original item and the adapted String are passed
*/
public WrappedTagReplacer(Collection<Tag<A>> allTags,
Collection<T> items,
Function<? super T, String> stringGetter,
BiFunction<T, String, ? extends T> itemCreator) {
this.items = items;
this.itemCreator = itemCreator;
List<String> stringItems = items.stream().map(stringGetter).collect(Collectors.toList());
tagReplacer = TagReplacer.newReplacer(allTags, stringItems);
}
/**
* Creates adapted items for the given argument.
*
* @param argument the argument to adapt the items for
* @return the adapted items
*/
public List<T> getAdaptedItems(A argument) {
List<String> adaptedStrings = tagReplacer.getAdaptedMessages(argument);
List<T> adaptedItems = new LinkedList<>();
Iterator<T> originalItemsIter = items.iterator();
Iterator<String> newStringsIter = adaptedStrings.iterator();
while (originalItemsIter.hasNext() && newStringsIter.hasNext()) {
adaptedItems.add(itemCreator.apply(originalItemsIter.next(), newStringsIter.next()));
}
return adaptedItems;
}
}