001package fr.aumgn.bukkitutils.command; 002 003import java.lang.reflect.Method; 004import java.util.Locale; 005 006import org.apache.commons.lang.Validate; 007import org.bukkit.command.CommandExecutor; 008import org.bukkit.command.CommandSender; 009import org.bukkit.command.PluginCommand; 010import org.bukkit.plugin.java.JavaPlugin; 011 012import fr.aumgn.bukkitutils.command.args.CommandArgs; 013import fr.aumgn.bukkitutils.command.executor.MethodCommandExecutor; 014import fr.aumgn.bukkitutils.command.executor.NestedCommandExecutor; 015 016/** 017 * Class which handles all the mess of registering commands and nested commands 018 * using the Bukkit API. 019 */ 020public class CommandsRegistration { 021 022 private static final String PREEXECUTE_METHOD_NAME = "preExecute"; 023 024 private final JavaPlugin plugin; 025 private final CommandsMessages messages; 026 027 public CommandsRegistration(JavaPlugin plugin, Locale locale) { 028 this.plugin = plugin; 029 CommandsLocalization localisation = 030 new CommandsLocalization(plugin, locale); 031 this.messages = localisation.get("commands"); 032 } 033 034 /** 035 * Registers all defined command in the given {@link Commands} object. 036 */ 037 public void register(Commands commands) { 038 Method preExecute = getPreExecuteMethod(commands); 039 040 String cmdPrefix = ""; 041 if (commands.getClass().isAnnotationPresent(NestedCommands.class)) { 042 cmdPrefix = registerNestedCommand(commands, preExecute); 043 } 044 045 046 for (Method method : commands.getClass().getDeclaredMethods()) { 047 if (!method.isAnnotationPresent(Command.class)) { 048 continue; 049 } 050 051 Command cmdAnnotation = method.getAnnotation(Command.class); 052 validateCommand(method, false); 053 Validate.notEmpty(cmdAnnotation.name()); 054 055 String cmdName = cmdPrefix + cmdAnnotation.name(); 056 PluginCommand command = plugin.getCommand(cmdName); 057 Validate.notNull(command, 058 String.format("Command '%s' does not exist", cmdName)); 059 060 if (command != null) { 061 CommandExecutor executor = new MethodCommandExecutor( 062 messages, commands, preExecute, method, cmdAnnotation); 063 setCommand(command, executor); 064 } 065 } 066 } 067 068 private Method getPreExecuteMethod(Commands commands) { 069 try { 070 Method preExecute = commands.getClass().getMethod( 071 PREEXECUTE_METHOD_NAME, CommandSender.class, 072 CommandArgs.class); 073 validateCommand(preExecute, true); 074 return preExecute; 075 } catch (NoSuchMethodException exc) { 076 return null; 077 } 078 } 079 080 private String registerNestedCommand(Commands commands, 081 Method preExecute) { 082 NestedCommands annotation = 083 commands.getClass().getAnnotation(NestedCommands.class); 084 String[] nestedCmds = annotation.value(); 085 Validate.notEmpty(nestedCmds); 086 Validate.notEmpty(nestedCmds[0]); 087 088 StringBuilder fullName = new StringBuilder(); 089 090 NestedCommandExecutor nestedExecutor = null; 091 for (String name : nestedCmds) { 092 Validate.notEmpty(name); 093 fullName.append(name); 094 095 PluginCommand command = plugin.getCommand(fullName.toString()); 096 Validate.notNull(command, String.format( 097 "Command '%s' does not exist", name)); 098 CommandExecutor executor = command.getExecutor(); 099 if (executor instanceof NestedCommandExecutor) { 100 nestedExecutor = (NestedCommandExecutor) executor; 101 } else { 102 nestedExecutor = new NestedCommandExecutor(plugin, messages, 103 annotation.defaultTo()); 104 setCommand(command, nestedExecutor); 105 } 106 fullName.append(" "); 107 } 108 109 return fullName.toString(); 110 } 111 112 private void setCommand(PluginCommand command, CommandExecutor executor) { 113 CommandExecutor oldExecutor = command.getExecutor(); 114 command.setExecutor(executor); 115 if (oldExecutor instanceof MethodCommandExecutor 116 || oldExecutor instanceof MethodCommandExecutor) { 117 return; 118 } 119 120 command.setUsage(messages.usageMessage(command.getUsage())); 121 command.setPermissionMessage(messages.permissionMessage()); 122 } 123 124 private void validateCommand(Method method, boolean strictLength) { 125 Class<?>[] params = method.getParameterTypes(); 126 if (strictLength) { 127 Validate.isTrue(params.length == 2, 128 "Command method must define two parameters."); 129 } else { 130 Validate.isTrue(params.length == 1 || params.length == 2, 131 "Command method must define one or two parameter(s)."); 132 } 133 Validate.isTrue(CommandSender.class.isAssignableFrom(params[0]), 134 "First parameter of command method must " 135 + "be of type CommandSender"); 136 Validate.isTrue(params.length == 1 137 || CommandArgs.class.isAssignableFrom(params[1]), 138 "Second parameter of command method must " 139 + "be of type CommandArgs"); 140 } 141}