Java tutorial
/* * PermissionsEx - Permissions plugin for Bukkit * Copyright (C) 2011 t3hk0d3 http://www.tehkode.ru * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ru.tehkode.permissions.bukkit.commands; import com.google.common.collect.Iterables; import com.mojang.api.profiles.HttpProfileRepository; import com.mojang.api.profiles.Profile; import com.mojang.api.profiles.ProfileRepository; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import ru.tehkode.permissions.PermissionsUserData; import ru.tehkode.permissions.backends.PermissionBackend; import ru.tehkode.permissions.PermissionManager; import ru.tehkode.permissions.bukkit.ErrorReport; import ru.tehkode.permissions.bukkit.PermissionsEx; import ru.tehkode.permissions.commands.Command; import ru.tehkode.permissions.commands.CommandsManager.CommandBinding; import ru.tehkode.permissions.exceptions.PermissionBackendException; import java.io.File; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; public class UtilityCommands extends PermissionsCommand { @Command(name = "pex", syntax = "reload", permission = "permissions.manage.reload", description = "Reload environment") public void reload(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { try { plugin.getPermissionsManager().reset(); sender.sendMessage(ChatColor.WHITE + "Permissions reloaded"); } catch (PermissionBackendException e) { sender.sendMessage(ChatColor.RED + "Failed to reload permissions! Check configuration!\n" + ChatColor.RED + "Error (see console for full): " + e.getMessage()); plugin.getLogger().log(Level.WARNING, "Failed to reload permissions when " + sender.getName() + " ran `pex reload`", e); } } @Command(name = "pex", syntax = "report", permission = "permissions.manage.reportbug", description = "Create an issue template to report an issue") public void report(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { ErrorReport report = ErrorReport.withException("User-requested report", new Exception().fillInStackTrace()); sender.sendMessage("Fill in the information at " + report.getShortURL() + " to report an issue"); sender.sendMessage(ChatColor.RED + "NOTE: A GitHub account is necessary to report issues. Create one at https://github.com/"); } @Command(name = "pex", syntax = "config <node> [value]", permission = "permissions.manage.config", description = "Print or set <node> [value]") public void config(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { String nodeName = args.get("node"); if (nodeName == null || nodeName.isEmpty()) { return; } FileConfiguration config = plugin.getConfig(); if (args.get("value") != null) { config.set(nodeName, this.parseValue(args.get("value"))); try { config.save(new File(plugin.getDataFolder(), "config.yml")); } catch (Throwable e) { sender.sendMessage( ChatColor.RED + "[PermissionsEx] Failed to save configuration: " + e.getMessage()); } } Object node = config.get(nodeName); if (node instanceof Map) { sender.sendMessage("Node \"" + nodeName + "\": "); for (Map.Entry<?, ?> entry : ((Map<?, ?>) node).entrySet()) { sender.sendMessage(" " + entry.getKey() + " = " + entry.getValue()); } } else if (node instanceof List) { sender.sendMessage("Node \"" + nodeName + "\": "); for (Object item : ((List<?>) node)) { sender.sendMessage(" - " + item); } } else { sender.sendMessage("Node \"" + nodeName + "\" = \"" + node + "\""); } } @Command(name = "pex", syntax = "backend", permission = "permissions.manage.backend", description = "Print currently used backend") public void getBackend(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { sender.sendMessage("Current backend: " + plugin.getPermissionsManager().getBackend()); } @Command(name = "pex", syntax = "backend <backend>", permission = "permissions.manage.backend", description = "Change permission backend on the fly (Use with caution!)") public void setBackend(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { if (args.get("backend") == null) { return; } try { plugin.getPermissionsManager().setBackend(args.get("backend")); sender.sendMessage(ChatColor.WHITE + "Permission backend changed!"); } catch (RuntimeException e) { if (e.getCause() instanceof ClassNotFoundException) { sender.sendMessage(ChatColor.RED + "Specified backend not found."); } else { sender.sendMessage(ChatColor.RED + "Error during backend initialization."); e.printStackTrace(); } } catch (PermissionBackendException e) { sender.sendMessage(ChatColor.RED + "Backend initialization failed! Fix your configuration!\n" + ChatColor.RED + "Error (see console for more): " + e.getMessage()); plugin.getLogger().log(Level.WARNING, "Backend initialization failed when " + sender.getName() + " was initializing " + args.get("backend"), e); } } @Command(name = "pex", syntax = "hierarchy [world]", permission = "permissions.manage.users", description = "Print complete user/group hierarchy") public void printHierarchy(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { sender.sendMessage("User/Group inheritance hierarchy:"); this.sendMessage(sender, this.printHierarchy(null, this.autoCompleteWorldName(args.get("world")), 0)); } @Command(name = "pex", syntax = "convert uuid [force]", permission = "permissions.convert", description = "Bulk convert user data to UUID-based storage") public void convertUUID(final PermissionsEx plugin, final CommandSender sender, Map<String, String> args) { final PermissionBackend backend = plugin.getPermissionsManager().getBackend(); if (!plugin.getServer().getOnlineMode() && !"force".equals(args.get("force"))) { sender.sendMessage(ChatColor.RED + "This server is running in offline mode and UUIDs may not be stable. Please run '/pex convert uuid force' to perform conversion anyway, or switch to online mode."); return; } final ProfileRepository repo = new HttpProfileRepository("minecraft"); final Collection<String> userIdentifiers = new HashSet<>(backend.getUserIdentifiers()); for (Iterator<String> it = userIdentifiers.iterator(); it.hasNext();) { try { UUID.fromString(it.next()); it.remove(); } catch (IllegalArgumentException ex) { } } if (userIdentifiers.isEmpty()) { sender.sendMessage(ChatColor.RED + "No users to convert!"); return; } sender.sendMessage("Beginning conversion to UUID in " + (int) Math.ceil(userIdentifiers.size() / 50000.0) + " batches of max 50k (1 batch is executed every 10 minutes)"); backend.setPersistent(false); final Iterator<List<String>> splitIdentifiers = Iterables.partition(userIdentifiers, 50 * 1000).iterator(); // 50k users per 10 minutes final AtomicInteger batchNum = new AtomicInteger(1); plugin.getPermissionsManager().getExecutor().execute(new Runnable() { @Override public void run() { List<String> names = splitIdentifiers.next(); try { for (Profile profile : repo.findProfilesByNames(names.toArray(new String[names.size()]))) { PermissionsUserData data = backend.getUserData(profile.getName()); data.setIdentifier(profile.getId().replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); data.setOption("name", profile.getName(), null); } } catch (Exception e) { ErrorReport.handleError("While converting batch " + batchNum.get() + " to UUID", e); backend.setPersistent(true); return; } if (splitIdentifiers.hasNext()) { plugin.getPermissionsManager().getExecutor().schedule(this, 10, TimeUnit.MINUTES); plugin.getLogger().info("Completed conversion batch " + batchNum.getAndIncrement() + " of " + (int) Math.ceil(userIdentifiers.size() / 50000.0)); } else { plugin.getLogger().info("UUID conversion complete"); if (!(sender instanceof Player) || ((Player) sender).isOnline()) { sender.sendMessage("UUID conversion complete"); } backend.setPersistent(true); } } }); } @Command(name = "pex", syntax = "import <backend>", permission = "permissions.dump", description = "Import data from <backend> as specified in the configuration") public void dumpData(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { try { PermissionManager mgr = plugin.getPermissionsManager(); PermissionBackend backend = mgr.createBackend(args.get("backend")); mgr.getBackend().loadFrom(backend); sender.sendMessage(ChatColor.WHITE + "[PermissionsEx] Data from \"" + args.get("backend") + "\" loaded into currently active backend"); } catch (RuntimeException e) { if (e.getCause() instanceof ClassNotFoundException) { sender.sendMessage(ChatColor.RED + "Specified backend not found!"); } else { sender.sendMessage(ChatColor.RED + "Error: " + e.getMessage()); plugin.getLogger().severe("Error: " + e.getMessage()); e.printStackTrace(); } } catch (PermissionBackendException e) { sender.sendMessage(ChatColor.RED + "Backend " + args.get("backend") + " was unable to load due to user configuration error. See console for details."); plugin.getLogger().log(Level.WARNING, "Import backend unable to load", e); } } @Command(name = "pex", syntax = "toggle debug", permission = "permissions.debug", description = "Enable/disable debug mode") public void toggleFeature(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { PermissionManager manager = plugin.getPermissionsManager(); manager.setDebug(!manager.isDebug()); String debugStatusMessage = "Debug mode " + (manager.isDebug() ? "enabled" : "disabled"); if (sender instanceof Player) { sender.sendMessage(debugStatusMessage); } plugin.getLogger().warning(debugStatusMessage); } private static int tryGetInt(CommandSender sender, Map<String, String> args, String key, int def) { if (!args.containsKey(key)) { return def; } try { return Integer.parseInt(args.get(key)); } catch (NumberFormatException e) { sender.sendMessage(ChatColor.RED + "Invalid " + key + " entered; must be an integer but was '" + args.get(key) + "'"); return Integer.MIN_VALUE; } } @Command(name = "pex", syntax = "help [page] [count]", permission = "permissions.manage", description = "PermissionsEx commands help") public void showHelp(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { List<CommandBinding> commands = this.manager.getCommands(); int count = tryGetInt(sender, args, "count", 4); int page = tryGetInt(sender, args, "page", 1); if (page == Integer.MIN_VALUE || count == Integer.MIN_VALUE) { return; // method already prints error message } if (page < 1) { sender.sendMessage(ChatColor.RED + "Page couldn't be lower than 1"); return; } int totalPages = (int) Math.ceil(commands.size() / count); sender.sendMessage(ChatColor.BLUE + "PermissionsEx" + ChatColor.WHITE + " commands (page " + ChatColor.GOLD + page + "/" + totalPages + ChatColor.WHITE + "): "); int base = count * (page - 1); for (int i = base; i < base + count; i++) { if (i >= commands.size()) { break; } Command command = commands.get(i).getMethodAnnotation(); String commandName = String.format("/%s %s", command.name(), command.syntax()) .replace("<", ChatColor.BOLD.toString() + ChatColor.RED + "<") .replace(">", ">" + ChatColor.RESET + ChatColor.GOLD.toString()) .replace("[", ChatColor.BOLD.toString() + ChatColor.BLUE + "[") .replace("]", "]" + ChatColor.RESET + ChatColor.GOLD.toString()); sender.sendMessage(ChatColor.GOLD + commandName); sender.sendMessage(ChatColor.AQUA + " " + command.description()); } } @Command(name = "pex", syntax = "version", permission = "permissions.manage", description = "Display version of PermissionsEx") public void showVersion(PermissionsEx plugin, CommandSender sender, Map<String, String> args) { if (sender instanceof Player) { sender.sendMessage("[" + ChatColor.RED + "PermissionsEx" + ChatColor.WHITE + "] version [" + ChatColor.BLUE + plugin.getDescription().getVersion() + ChatColor.WHITE + "]"); } else { sender.sendMessage("[PermissionsEx] version [" + plugin.getDescription().getVersion() + "]"); } } }