package org.manalith.ircbot.plugin; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Optional; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.ArrayUtils; import org.manalith.ircbot.annotation.Option; import org.manalith.ircbot.common.stereotype.BotCommand; import org.manalith.ircbot.common.stereotype.BotCommand.BotEvent; import org.manalith.ircbot.resources.MessageEvent; /** * 어노테이션(@BotCommand) 기반 명령을 위한 메서드 래퍼 */ public class Command { private Plugin plugin; private Method method; private BotCommand meta; private String[] aliases; private String[] params; private int minimumArguments; public Command(Method method, Plugin plugin) { this.method = method; this.plugin = plugin; meta = method.getAnnotation(BotCommand.class); aliases = ArrayUtils.add(meta.value(), method.getName().toLowerCase()); for (int i = 0; i < aliases.length; i++) { aliases[i] = EventDispatcher.COMMAND_PREFIX + aliases[i]; } Class<?>[] types = method.getParameterTypes(); Annotation[][] annotations = method.getParameterAnnotations(); List<String> params = new ArrayList<>(); for (int i = 0; i < types.length; i++) { Annotation[] ann = annotations[i]; Class<?> type = types[i]; if (type == MessageEvent.class) continue; String name = null; boolean isRequired = false; if (type != Optional.class) { minimumArguments++; isRequired = true; } for (Annotation a : ann) { if (a instanceof Option) name = ((Option) a).name(); } if (name == null) name = "arg" + i; if (isRequired) name = "*" + name; name = "[" + name + "]"; params.add(name); } this.params = params.toArray(new String[] {}); } public BotCommand getMeta() { return meta; } public String[] getAliases() { return aliases; } public BotEvent[] getListeners() { return meta.listeners(); } public boolean matches(String alias, BotEvent event) { return ArrayUtils.contains(getListeners(), event) && ArrayUtils.contains(aliases, alias); } public String getUsage() { return "사용법 : " + StringUtils.join(aliases, '|') + " " + StringUtils.join(params, ' '); } public String execute(MessageEvent event, String[] params) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (params.length < minimumArguments) return getUsage(); String result = null; switch (method.getParameterTypes().length) { case 0: result = (String) method.invoke(plugin); break; case 1: { Class<?> type = method.getParameterTypes()[0]; if (type == MessageEvent.class) result = (String) method.invoke(plugin, event); else if (type.isArray()) result = (String) method.invoke(plugin, (Object) params); else result = (String) method.invoke(plugin, StringUtils.join(params, " ")); break; } default: // event, param // event, params[] // event, param, params[] // param, param // param, param, params[] // ... List<Class<?>> args = Arrays.asList(method.getParameterTypes()); Iterator<Class<?>> ai = args.iterator(); List<String> inputs = Arrays.asList(params); ListIterator<String> ii = inputs.listIterator(); List<Object> newParams = new ArrayList<>(); while (ai.hasNext()) { Class<?> arg = ai.next(); if (arg == MessageEvent.class) { newParams.add(event); } else { if (!ai.hasNext() && ii.hasNext()) { List<String> more = new ArrayList<>(); while (ii.hasNext()) { more.add(ii.next()); } if (arg.isArray()) { newParams.add(more.toArray(new String[] {})); } else { newParams.add(StringUtils.join(more, ' ')); } } else { newParams.add(ii.next()); } } } // result = (String) method.invoke(plugin, event, // method.getParameterTypes()[1].isArray() ? params // : StringUtils.join(params)); result = (String) method.invoke(plugin, newParams.toArray()); } if (StringUtils.isNotBlank(result)) return result; event.setExecuted(meta.stopEvent()); return ""; } }