Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-26 02:50:06 +01:00
Added support for using instances (created using a specified dependency injector) in CommandsManager.
Dieser Commit ist enthalten in:
Ursprung
1784b29f02
Commit
86ecd49b89
@ -21,60 +21,80 @@ package com.sk89q.minecraft.util.commands;
|
|||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Map;
|
import java.util.logging.Level;
|
||||||
import java.util.Set;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.sk89q.util.StringUtil;
|
import com.sk89q.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager for handling commands. This allows you to easily process commands,
|
* <p>Manager for handling commands. This allows you to easily process commands,
|
||||||
* including nested commands, by correctly annotating methods of a class.
|
* including nested commands, by correctly annotating methods of a class.</p>
|
||||||
* The commands are thus declaratively defined, and it's easy to spot
|
|
||||||
* how permissions and commands work out, and it decreases the opportunity
|
|
||||||
* for errors because the consistency would cause any odd balls to show.
|
|
||||||
* The manager also handles some boilerplate code such as number of arguments
|
|
||||||
* checking and printing usage.
|
|
||||||
*
|
*
|
||||||
* <p>To use this, it is merely a matter of registering classes containing
|
* <p>To use this, it is merely a matter of registering classes containing
|
||||||
* the commands (as methods with the proper annotations) with the
|
* the commands (as methods with the proper annotations) with the
|
||||||
* manager. When you want to process a command, use one of the
|
* manager. When you want to process a command, use one of the
|
||||||
* <code>execute</code> methods. If something is wrong, such as incorrect
|
* <code>execute</code> methods. If something is wrong, such as incorrect
|
||||||
* usage, insufficient permissions, or a missing command altogether, an
|
* usage, insufficient permissions, or a missing command altogether, an
|
||||||
* exception will be raised for upstream handling.
|
* exception will be raised for upstream handling.</p>
|
||||||
|
*
|
||||||
|
* <p>Methods of a class to be registered can be static, but if an injector
|
||||||
|
* is registered with the class, the instances of the command classes
|
||||||
|
* will be created automatically and methods will be called non-statically.</p>
|
||||||
*
|
*
|
||||||
* <p>To mark a method as a command, use {@link Command}. For nested commands,
|
* <p>To mark a method as a command, use {@link Command}. For nested commands,
|
||||||
* see {@link NestedCommand}. To handle permissions, use
|
* see {@link NestedCommand}. To handle permissions, use
|
||||||
* {@link CommandPermissions}.
|
* {@link CommandPermissions}.</p>
|
||||||
*
|
*
|
||||||
* <p>This uses Java reflection extensively, but to reduce the overhead of
|
* <p>This uses Java reflection extensively, but to reduce the overhead of
|
||||||
* reflection, command lookups are completely cached on registration. This
|
* reflection, command lookups are completely cached on registration. This
|
||||||
* allows for fast command handling. Method invocation still has to be done
|
* allows for fast command handling. Method invocation still has to be done
|
||||||
* with reflection, but this is quite fast in that of itself.
|
* with reflection, but this is quite fast in that of itself.</p>
|
||||||
*
|
*
|
||||||
* @author sk89q
|
* @author sk89q
|
||||||
* @param <T> command sender class
|
* @param <T> command sender class
|
||||||
*/
|
*/
|
||||||
public abstract class CommandsManager<T> {
|
public abstract class CommandsManager<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for general errors.
|
||||||
|
*/
|
||||||
|
protected static final Logger logger =
|
||||||
|
Logger.getLogger(CommandsManager.class.getCanonicalName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping of commands (including aliases) with a description. Root
|
* Mapping of commands (including aliases) with a description. Root
|
||||||
* commands are stored under a key of null, whereas child commands are
|
* commands are stored under a key of null, whereas child commands are
|
||||||
* cached under their respective {@link Method}.
|
* cached under their respective {@link Method}. The child map has
|
||||||
|
* the key of the command name (one for each alias) with the
|
||||||
|
* method.
|
||||||
*/
|
*/
|
||||||
protected Map<Method, Map<String, Method>> commands
|
protected Map<Method, Map<String, Method>> commands
|
||||||
= new HashMap<Method, Map<String, Method>>();
|
= new HashMap<Method, Map<String, Method>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping of commands (not including aliases) with a description.
|
* Used to store the instances associated with a method.
|
||||||
|
*/
|
||||||
|
protected Map<Method, Object> instances = new HashMap<Method, Object>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping of commands (not including aliases) with a description. This
|
||||||
|
* is only for top level commands.
|
||||||
*/
|
*/
|
||||||
protected Map<String, String> descs = new HashMap<String, String>();
|
protected Map<String, String> descs = new HashMap<String, String>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register an object that contains commands (denoted by
|
* Stores the injector used to getInstance.
|
||||||
* {@link Command}. The methods are
|
*/
|
||||||
* cached into a map for later usage and it reduces the overhead of
|
protected Injector injector;
|
||||||
* reflection (method lookup via reflection is relatively slow).
|
|
||||||
|
/**
|
||||||
|
* Register an class that contains commands (denoted by {@link Command}.
|
||||||
|
* If no dependency injector is specified, then the methods of the
|
||||||
|
* class will be registered to be called statically. Otherwise, new
|
||||||
|
* instances will be created of the command classes and methods will
|
||||||
|
* not be called statically.
|
||||||
*
|
*
|
||||||
* @param cls
|
* @param cls
|
||||||
*/
|
*/
|
||||||
@ -83,12 +103,37 @@ public abstract class CommandsManager<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the methods of a class.
|
* Register the methods of a class. This will automatically construct
|
||||||
|
* instances as necessary.
|
||||||
*
|
*
|
||||||
* @param cls
|
* @param cls
|
||||||
* @param parent
|
* @param parent
|
||||||
*/
|
*/
|
||||||
private void registerMethods(Class<?> cls, Method parent) {
|
private void registerMethods(Class<?> cls, Method parent) {
|
||||||
|
try {
|
||||||
|
if (getInjector() == null) {
|
||||||
|
registerMethods(cls, parent, null);
|
||||||
|
} else {
|
||||||
|
Object obj = null;
|
||||||
|
obj = getInjector().getInstance(cls);
|
||||||
|
registerMethods(cls, parent, obj);
|
||||||
|
}
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to register commands", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to register commands", e);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to register commands", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the methods of a class.
|
||||||
|
*
|
||||||
|
* @param cls
|
||||||
|
* @param parent
|
||||||
|
*/
|
||||||
|
private void registerMethods(Class<?> cls, Method parent, Object obj) {
|
||||||
Map<String, Method> map;
|
Map<String, Method> map;
|
||||||
|
|
||||||
// Make a new hash map to cache the commands for this class
|
// Make a new hash map to cache the commands for this class
|
||||||
@ -105,6 +150,8 @@ public abstract class CommandsManager<T> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isStatic = Modifier.isStatic(method.getModifiers());
|
||||||
|
|
||||||
Command cmd = method.getAnnotation(Command.class);
|
Command cmd = method.getAnnotation(Command.class);
|
||||||
|
|
||||||
// Cache the aliases too
|
// Cache the aliases too
|
||||||
@ -112,6 +159,16 @@ public abstract class CommandsManager<T> {
|
|||||||
map.put(alias, method);
|
map.put(alias, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want to be able invoke with an instance
|
||||||
|
if (!isStatic) {
|
||||||
|
// Can't register this command if we don't have an instance
|
||||||
|
if (obj == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.put(method, obj);
|
||||||
|
}
|
||||||
|
|
||||||
// Build a list of commands and their usage details, at least for
|
// Build a list of commands and their usage details, at least for
|
||||||
// root level commands
|
// root level commands
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
@ -339,12 +396,14 @@ public abstract class CommandsManager<T> {
|
|||||||
|
|
||||||
methodArgs[0] = context;
|
methodArgs[0] = context;
|
||||||
|
|
||||||
|
Object instance = instances.get(method);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
method.invoke(null, methodArgs);
|
method.invoke(instance, methodArgs);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
e.printStackTrace();
|
logger.log(Level.SEVERE, "Failed to execute command", e);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
logger.log(Level.SEVERE, "Failed to execute command", e);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof CommandException) {
|
if (e.getCause() instanceof CommandException) {
|
||||||
throw (CommandException) e.getCause();
|
throw (CommandException) e.getCause();
|
||||||
@ -385,4 +444,21 @@ public abstract class CommandsManager<T> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract boolean hasPermission(T player, String perm);
|
public abstract boolean hasPermission(T player, String perm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the injector used to create new instances. This can be
|
||||||
|
* null, in which case only classes will be registered statically.
|
||||||
|
*/
|
||||||
|
public Injector getInjector() {
|
||||||
|
return injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the injector for creating new instances.
|
||||||
|
*
|
||||||
|
* @param injector injector or null
|
||||||
|
*/
|
||||||
|
public void setInjector(Injector injector) {
|
||||||
|
this.injector = injector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
28
src/main/java/com/sk89q/minecraft/util/commands/Injector.java
Normale Datei
28
src/main/java/com/sk89q/minecraft/util/commands/Injector.java
Normale Datei
@ -0,0 +1,28 @@
|
|||||||
|
// $Id$
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.minecraft.util.commands;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs new instances.
|
||||||
|
*/
|
||||||
|
public interface Injector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of the given class.
|
||||||
|
*
|
||||||
|
* @param cls class
|
||||||
|
* @return object
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws InstantiationException
|
||||||
|
* @throws InvocationTargetException
|
||||||
|
*/
|
||||||
|
public Object getInstance(Class<?> cls) throws InvocationTargetException,
|
||||||
|
IllegalAccessException, InstantiationException;
|
||||||
|
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren