diff --git a/pom.xml b/pom.xml
index a1f4babf..0d0dc9dd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,8 +43,8 @@
UTF-8
- 1.7
- 1.7
+ 1.8
+ 1.8
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/Command.java b/src/main/java/fr/zcraft/zlib/components/commands2/Command.java
new file mode 100644
index 00000000..2a9706b4
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/Command.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.exceptions.CommandException;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * This class represents a registered command.
+ * @param The command runnable type this command is bound to.
+ */
+public class Command {
+
+ private final String name;
+ private final Class runnableClass;
+ private final boolean isCommandGroup;
+ private final List> subCommands;
+ private final List parameters;
+ private final List flags;
+
+ Command(Class runnableClass, String name, boolean isCommandGroup, List> subCommands, List parameters, List flags) {
+ this.runnableClass = runnableClass;
+ this.name = name;
+ this.isCommandGroup = isCommandGroup;
+ this.subCommands = subCommands;
+ this.parameters = parameters;
+ this.flags = flags;
+ }
+
+ public Context extends CommandRunnable> makeContext(CommandSender sender, String[] arguments) throws CommandException {
+ return ContextGenerator.makeContext(this, sender, arguments, Optional.empty());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean nameMatches(String string) {
+ return string.equalsIgnoreCase(name);
+ }
+
+ public Class getRunnableClass() {
+ return runnableClass;
+ }
+
+ public boolean isCommandGroup() {
+ return isCommandGroup;
+ }
+
+ public List> getSubCommands() {
+ return subCommands;
+ }
+
+ public Optional> getSubCommand(String name) {
+ for(SubCommand, T> subCommand : subCommands) {
+ if(subCommand.getCommand().nameMatches(name)) return Optional.of(subCommand);
+ }
+ return Optional.empty();
+ }
+
+ public List getParameters() {
+ return parameters;
+ }
+
+ public List getFlags() {
+ return flags;
+ }
+
+ public Optional getFlag(String shortName) {
+ for(Flag flag: flags) {
+ if(flag.getName().equals(shortName)) return Optional.of(flag);
+ }
+ return Optional.empty();
+ }
+
+ public Optional getShortFlag(String shortName) {
+ for(Flag flag: flags) {
+ if(flag.getShortName().equals(shortName)) return Optional.of(flag);
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/CommandExecutor.java b/src/main/java/fr/zcraft/zlib/components/commands2/CommandExecutor.java
new file mode 100644
index 00000000..9b8ee528
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/CommandExecutor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+import java.util.List;
+
+class CommandExecutor implements TabCompleter, org.bukkit.command.CommandExecutor {
+
+ public CommandExecutor(Command command) {
+
+ }
+
+ @Override
+ public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/CommandGenerator.java b/src/main/java/fr/zcraft/zlib/components/commands2/CommandGenerator.java
new file mode 100644
index 00000000..f8b7fee5
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/CommandGenerator.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.annotations.Subcommand;
+import fr.zcraft.zlib.components.commands2.exceptions.CommandConfigurationException;
+import fr.zcraft.zlib.components.commands2.exceptions.UnhandledParameterType;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * This class contains various utilities to generate Command objects from their bound runnable class.
+ */
+class CommandGenerator {
+ static public Command fromClass(Class runnableClass, String name) {
+ if(isCommandGroup(runnableClass)) {
+ return fromEnumClass(runnableClass, name);
+ } else {
+ return fromPlainClass(runnableClass, name);
+ }
+ }
+
+ static private boolean isCommandGroup(Class extends CommandRunnable> runnableClass) {
+ return Enum.class.isAssignableFrom(runnableClass);
+ }
+
+ static private Command fromEnumClass(final Class runnableClass, String name) {
+ List> subcommands = Arrays.stream(runnableClass.getDeclaredFields())
+ .filter(Field::isEnumConstant)
+ .map(f -> subcommandFromField(f, runnableClass))
+ .collect(Collectors.toList());
+
+ return new Command<>(runnableClass, name, true, subcommands, new ArrayList<>(), new ArrayList<>());
+ }
+
+ static private List getCommandParameters(Class extends CommandRunnable> runnableClass) throws UnhandledParameterType {
+ return Arrays.stream(runnableClass.getDeclaredFields())
+ .filter(f -> !isFlagField(f))
+ .map(CommandGenerator::parameterFromField)
+ .collect(Collectors.toList());
+ }
+
+ static private List getCommandFlags(Class extends CommandRunnable> runnableClass) throws UnhandledParameterType {
+ return Arrays.stream(runnableClass.getDeclaredFields())
+ .filter(CommandGenerator::isFlagField)
+ .map(CommandGenerator::flagFromField)
+ .collect(Collectors.toList());
+ }
+
+ static private boolean isFlagField(Field field) {
+ return field.getAnnotation(fr.zcraft.zlib.components.commands2.annotations.Flag.class) != null;
+ }
+
+ static private Parameter parameterFromField(Field field) throws UnhandledParameterType {
+ return new Parameter(field.getType(), field, findTypeConverter(field), field.getName(), null, isFieldRequired(field));
+ }
+
+ static private Flag flagFromField(Field field) throws UnhandledParameterType {
+ Class> type = field.getType();
+ fr.zcraft.zlib.components.commands2.annotations.Flag flagAnnotation = field.getAnnotation(fr.zcraft.zlib.components.commands2.annotations.Flag.class);
+ String shortName = flagAnnotation.shortName();
+
+ if(boolean.class.isAssignableFrom(type)) {
+ return new Flag(type, field, null, field.getName(), shortName,null, false, false);
+ }
+
+ boolean isRequired = isFieldRequired(field);
+ return new Flag(type, field, findTypeConverter(field), field.getName(), shortName, null, isRequired, true);
+ }
+
+ static private Class> getFieldType(Field field) {
+ Class> type = field.getType();
+ if(Optional.class.isAssignableFrom(type)) {
+ ParameterizedType ptype = (ParameterizedType) field.getGenericType();
+ type = (Class>) ptype.getActualTypeArguments()[0];
+ }
+ return type;
+ }
+
+ static private ParameterTypeConverter findTypeConverter(Field field) throws UnhandledParameterType {
+ Class> type = getFieldType(field);
+ Optional> typeConverter = Commands.findTypeConverter(type);
+ if(!typeConverter.isPresent()) throw new UnhandledParameterType(type, field);
+ return typeConverter.get();
+ }
+
+ static private boolean isFieldRequired(Field f) {
+ return !Optional.class.isAssignableFrom(f.getType());
+ }
+
+ static private Command fromPlainClass(Class runnableClass, String name) {
+ return new Command<>(runnableClass, name, false, new ArrayList<>(), getCommandParameters(runnableClass), getCommandFlags(runnableClass));
+ }
+
+ static private SubCommand, T> subcommandFromField(Field field, Class parentCommandClass) {
+ Subcommand subcommand = field.getAnnotation(Subcommand.class);
+ if(subcommand == null) throw new CommandConfigurationException(parentCommandClass, "Missing subcommand annotation on field: " + field.getName());
+
+ String commandName = subcommand.name();
+ if(commandName.isEmpty()) commandName = field.getName().toLowerCase();
+ Command> innerCommand = fromClass(subcommand.value(), commandName);
+ Object parentFieldValue;
+ try {
+ field.setAccessible(true);
+ parentFieldValue = field.get(null);
+ if(!parentCommandClass.isInstance(parentFieldValue)) {
+ throw new CommandConfigurationException(parentCommandClass, "Invalid enum field: " + field.getName());
+ }
+ } catch (IllegalAccessException e) {
+ throw new CommandConfigurationException(parentCommandClass, "Unable to access field: " + field.getName());
+ }
+
+ @SuppressWarnings ("unchecked")
+ T parentValue = (T) parentFieldValue;
+
+ return new SubCommand<>(innerCommand, parentValue, field);
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/CommandRunnable.java b/src/main/java/fr/zcraft/zlib/components/commands2/CommandRunnable.java
new file mode 100644
index 00000000..92476cbd
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/CommandRunnable.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.exceptions.CommandException;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+
+
+public interface CommandRunnable {
+ default void run(Context context) throws CommandException {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/CommandSender.java b/src/main/java/fr/zcraft/zlib/components/commands2/CommandSender.java
new file mode 100644
index 00000000..d87097de
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/CommandSender.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+public class CommandSender {
+ private org.bukkit.command.CommandSender bukkitSender;
+
+ CommandSender() {}
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/Commands.java b/src/main/java/fr/zcraft/zlib/components/commands2/Commands.java
new file mode 100644
index 00000000..f2a00e42
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/Commands.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.converters.IntegerTypeConverter;
+import fr.zcraft.zlib.components.commands2.converters.URITypeConverter;
+import fr.zcraft.zlib.components.commands2.exceptions.CommandException;
+import fr.zcraft.zlib.components.commands2.exceptions.CommandNotFoundException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * The entry point for the zLib Commands component.
+ */
+public abstract class Commands
+{
+ private Commands() {}
+
+ static private final Map> commandRegistry = new HashMap<>();
+ static private final Map, ParameterTypeConverter>> typeConverterRegistry = new HashMap<>();
+
+ /**
+ * Registers a new command.
+ * @param command The command runnable to be registered
+ * @param name The name of the command
+ */
+ static public void register(Class extends CommandRunnable> command, String name) {
+ name = name.toLowerCase();
+ if(commandRegistry.containsKey(name)) throw new IllegalArgumentException("Command already registered : " + name);
+
+ commandRegistry.put(name, CommandGenerator.fromClass(command, name));
+ }
+
+ /**
+ * Registers a new command parameter type converter.
+ * You must register a new converter before using any types in your commands that zLib doesn't support out of the box.
+ * Additional type converters must be registered before any commands using the type are.
+ * @param parameterTypeConverter The type converter to register
+ */
+ static public void registerParameterTypeConverter(ParameterTypeConverter> parameterTypeConverter) {
+ //TODO: Raise exception if already registered
+ typeConverterRegistry.put(parameterTypeConverter.getType(), parameterTypeConverter);
+ }
+
+ /**
+ * Finds the registered command matching the given name.
+ * @param commandName The name of the command
+ * @return The matching command
+ * @throws CommandNotFoundException If no matching command is found
+ */
+ static public Command findCommand(String commandName) throws CommandNotFoundException {
+ Command command = commandRegistry.get(commandName.toLowerCase());
+ if(command == null) throw new CommandNotFoundException(commandName);
+ return command;
+ }
+
+ /**
+ * Finds the registered command parameter type converter handling the given type.
+ * @param type The type used to look up the matching type converter
+ * @return The registered command parameter type converter, if found
+ */
+ static public Optional> findTypeConverter(Class> type) {
+ return Optional.ofNullable(typeConverterRegistry.get(type));
+ }
+
+ /**
+ * Creates a new Command execution context for the given command.
+ * @param commandName The name of the command
+ * @param sender The command sender the command originated from
+ * @param arguments The command arguments
+ * @return The newly created context
+ * @throws CommandException If the command is not found, or if an error occured when parsing the arguments
+ */
+ static public Context> makeContext(String commandName, CommandSender sender, String[] arguments) throws CommandException {
+ return findCommand(commandName).makeContext(sender, arguments);
+ }
+
+ // REGISTER ALL THE TYPES
+ static {
+ registerParameterTypeConverter(new IntegerTypeConverter());
+ registerParameterTypeConverter(new URITypeConverter());
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/Context.java b/src/main/java/fr/zcraft/zlib/components/commands2/Context.java
new file mode 100644
index 00000000..498e9717
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/Context.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import java.util.Optional;
+
+/**
+ * This class represents a command execution context.
+ * It contains all the data related to command execution, such as the command sender, arguments, etc.
+ * @param The command runnable type this command is bound to.
+ */
+public class Context {
+
+ private final T runnable;
+ private final CommandSender sender;
+ private final String[] args;
+ private final Command parentCommand;
+ private final Optional parentContext;
+ private final Optional> matchedSubCommand;
+
+ Context(T runnable, CommandSender sender, String[] args, Command command, Optional parentContext, Optional> matchedSubCommand) {
+ this.runnable = runnable;
+ this.sender = sender;
+ this.args = args;
+ this.parentCommand = command;
+ this.parentContext = parentContext;
+ this.matchedSubCommand = matchedSubCommand;
+ }
+
+ public T getCommandRunnable() {
+ return this.runnable;
+ }
+
+ public CommandSender sender() {
+ return this.sender;
+ }
+
+ public String[] getArgs() {
+ return args;
+ }
+
+ public Command getParentCommand() {
+ return parentCommand;
+ }
+
+ public Optional getParentContext() {
+ return parentContext;
+ }
+
+ public Optional> getMatchedSubCommand() {
+ return matchedSubCommand;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/ContextGenerator.java b/src/main/java/fr/zcraft/zlib/components/commands2/ContextGenerator.java
new file mode 100644
index 00000000..d9f54982
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/ContextGenerator.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.exceptions.*;
+import fr.zcraft.zlib.tools.reflection.Reflection;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * This class contains various utilities to generate Context objects from arguments matched against their bound Command class.
+ */
+abstract class ContextGenerator {
+ private ContextGenerator() {}
+
+ private static Context makeEnumContext(Command command, CommandSender sender, String[] arguments, Optional parentContext) throws ArgumentException {
+ if(arguments.length < 1) throw new MissingSubcommandException(command);
+ SubCommand, T> subCommand = command.getSubCommand(arguments[0]).orElseThrow(() -> new UnknownSubcommandException(command, arguments[0], 0));
+ return new Context<>(subCommand.getParentEnumValue(), sender, arguments, command, parentContext, Optional.of(subCommand));
+ }
+
+ static Context extends CommandRunnable> makeContext(Command extends CommandRunnable> command, CommandSender sender, String[] arguments, Optional parentContext) throws ArgumentException {
+ if(!command.isCommandGroup()) {
+ return makePlainClassContext(command, sender, arguments, parentContext);
+ }
+
+ Context> context = makeEnumContext(command, sender, arguments, parentContext);
+ SubCommand, ? extends CommandRunnable> subCommand = context.getMatchedSubCommand().orElseThrow(NullPointerException::new);
+ try {
+ return makeContext(subCommand.getCommand(), sender, Arrays.copyOfRange(arguments, 1, arguments.length), Optional.of(context));
+ } catch(ArgumentException e) {
+ e.setArgumentPosition(e.getArgumentPosition().map(i -> i + 1));
+ throw e;
+ }
+ }
+
+ private static Context makePlainClassContext(Command command, CommandSender sender, String[] arguments, Optional parentContext) throws ArgumentException {
+ T runnable = instanciateCommandRunnable(command);
+ List parameters = command.getParameters();
+ List flags = command.getFlags();
+ List remainingFlags = new ArrayList<>(flags);
+
+ int argumentsI = 0;
+ int parametersI = 0;
+
+ for(; argumentsI < arguments.length; ++argumentsI) {
+ String argument = arguments[argumentsI];
+ Flag flag = null;
+ if(argument.startsWith("--")) {
+ argument = argument.substring(2);
+ Optional oflag = command.getFlag(argument);
+ if (!oflag.isPresent()) throw new UnknownFlagException(argument, argumentsI);
+ flag = oflag.get();
+ } else if(argument.startsWith("-")) {
+ argument = argument.substring(1);
+ Optional oflag = command.getShortFlag(argument);
+ if (!oflag.isPresent()) throw new UnknownFlagException(argument, argumentsI);
+ flag = oflag.get();
+ }
+
+ if(flag != null) {
+ if (!remainingFlags.remove(flag)) throw new FlagAlreadyDefinedException(flag, argument, argumentsI);
+ if (!flag.hasValue()) {
+ setRunnableField(runnable, flag, true);
+ } else {
+ if (argumentsI + 1 >= arguments.length) throw new FlagMissingValueException(flag, argumentsI);
+ ++argumentsI;
+ Object runnableValue = convertFieldType(flag, arguments[argumentsI], argumentsI);
+ if (flag.isRequired()) {
+ setRunnableField(runnable, flag, runnableValue);
+ } else {
+ setRunnableField(runnable, flag, Optional.of(runnableValue));
+ }
+ }
+ continue;
+ }
+
+ if(parametersI >= parameters.size()) throw new ExtraArgumentException(arguments[argumentsI], argumentsI);
+ Parameter parameter = parameters.get(argumentsI);
+ setRunnableField(runnable, parameter, convertFieldType(parameter, arguments[argumentsI], argumentsI));
+ ++parametersI;
+ }
+
+ //Look for missing required parameters
+ for(; parametersI < parameters.size(); ++parametersI) {
+ Parameter parameter = parameters.get(parametersI);
+ if(parameter.isRequired()) {
+ throw new MissingParameterException(parameter);
+ }
+ setRunnableField(runnable, parameter, Optional.empty());
+ }
+
+ //Look for missing required flags
+ for(Flag f: remainingFlags) {
+ if(f.isRequired()) throw new MissingRequiredFlagException(f);
+ if(f.hasValue()) {
+ setRunnableField(runnable, f, Optional.empty());
+ } else {
+ setRunnableField(runnable, f, false);
+ }
+ }
+
+
+ return new Context<>(runnable, sender, arguments, command, parentContext, Optional.empty());
+ }
+
+ static private void setRunnableField(CommandRunnable runnable, Field field, Object value) {
+ try {
+ field.getRunnableField().set(runnable, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Unable to set runnable class field : " + runnable.getClass() + "." + field.getRunnableField().getName(), e);
+ }
+ }
+
+ static private T instanciateCommandRunnable(Command command) {
+ try {
+ return Reflection.instantiate(command.getRunnableClass());
+ } catch(Exception e) {
+ throw new RuntimeException("Unable to instanciate Command runnable class : " + command.getRunnableClass().getName(), e);
+ }
+ }
+
+ static private Object convertFieldType(Field parameter, String argument, int argumentPosition) throws InvalidArgumentException {
+ try {
+ return parameter.getTypeConverter().fromArgument(argument);
+ } catch (ParameterTypeConverterException e) {
+ throw new InvalidArgumentException(e, argument, argumentPosition);
+ }
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/Field.java b/src/main/java/fr/zcraft/zlib/components/commands2/Field.java
new file mode 100644
index 00000000..e235c283
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/Field.java
@@ -0,0 +1,45 @@
+package fr.zcraft.zlib.components.commands2;
+
+class Field {
+ private final Class> parameterType;
+ private final java.lang.reflect.Field runnableField;
+ private final ParameterTypeConverter> typeConverter;
+
+ private final String name;
+ private final String about;
+ private final boolean isRequired;
+
+ Field(Class> parameterType, java.lang.reflect.Field runnableField, ParameterTypeConverter> typeConverter, String name, String about, boolean isRequired) {
+ this.parameterType = parameterType;
+ this.runnableField = runnableField;
+ this.typeConverter = typeConverter;
+
+ this.name = name;
+ this.about = about;
+ this.isRequired = isRequired;
+ }
+
+ public Class> getParameterType() {
+ return parameterType;
+ }
+
+ public ParameterTypeConverter> getTypeConverter() {
+ return typeConverter;
+ }
+
+ public java.lang.reflect.Field getRunnableField() {
+ return runnableField;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getAbout() {
+ return about;
+ }
+
+ public boolean isRequired() {
+ return isRequired;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/Flag.java b/src/main/java/fr/zcraft/zlib/components/commands2/Flag.java
new file mode 100644
index 00000000..2bfcdcc8
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/Flag.java
@@ -0,0 +1,21 @@
+package fr.zcraft.zlib.components.commands2;
+
+public class Flag extends Field {
+ private final boolean hasValue;
+ private final String shortName;
+
+ Flag(Class> parameterType, java.lang.reflect.Field runnableField, ParameterTypeConverter> typeConverter, String name, String shortName, String about, boolean isRequired, boolean hasValue) {
+ super(parameterType, runnableField, typeConverter, name, about, isRequired);
+ this.hasValue = hasValue;
+ this.shortName = shortName;
+ }
+
+ public boolean hasValue() {
+ return hasValue;
+ }
+
+ public String getShortName() {
+ return shortName;
+ }
+}
+
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/Parameter.java b/src/main/java/fr/zcraft/zlib/components/commands2/Parameter.java
new file mode 100644
index 00000000..644dd25c
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/Parameter.java
@@ -0,0 +1,7 @@
+package fr.zcraft.zlib.components.commands2;
+
+public class Parameter extends Field {
+ Parameter(Class> parameterType, java.lang.reflect.Field runnableField, ParameterTypeConverter> typeConverter, String name, String about, boolean isRequired) {
+ super(parameterType, runnableField, typeConverter, name, about, isRequired);
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/ParameterTypeConverter.java b/src/main/java/fr/zcraft/zlib/components/commands2/ParameterTypeConverter.java
new file mode 100644
index 00000000..7ed872d7
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/ParameterTypeConverter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.exceptions.ParameterTypeConverterException;
+
+/**
+ * An interface used to parse types from command arguments.
+ * @param
+ */
+public interface ParameterTypeConverter {
+ Class getType();
+ T fromArgument(String argument) throws ParameterTypeConverterException;
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/SubCommand.java b/src/main/java/fr/zcraft/zlib/components/commands2/SubCommand.java
new file mode 100644
index 00000000..a14454c3
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/SubCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import java.lang.reflect.Field;
+
+/**
+ * This class contains information about a command's subcommand.
+ * @param
+ * @param
+ */
+public class SubCommand {
+ private final Command command;
+ private final Parent parentEnumValue;
+ private final Field parentField;
+
+ SubCommand(Command command, Parent parentEnumValue, Field parentField) {
+ this.command = command;
+ this.parentEnumValue = parentEnumValue;
+ this.parentField = parentField;
+ }
+
+ public Command getCommand() {
+ return command;
+ }
+
+ public Parent getParentEnumValue() {
+ return parentEnumValue;
+ }
+
+ public Field getParentField() {
+ return parentField;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/annotations/About.java b/src/main/java/fr/zcraft/zlib/components/commands2/annotations/About.java
new file mode 100644
index 00000000..1af8b9d7
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/annotations/About.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface About {
+ String value();
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/annotations/Flag.java b/src/main/java/fr/zcraft/zlib/components/commands2/annotations/Flag.java
new file mode 100644
index 00000000..d1dce9c5
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/annotations/Flag.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Flag {
+ String shortName() default "";
+ String name() default "";
+ String[] names() default {};
+ String[] additionalNames() default {};
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/annotations/Subcommand.java b/src/main/java/fr/zcraft/zlib/components/commands2/annotations/Subcommand.java
new file mode 100644
index 00000000..2eef68a3
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/annotations/Subcommand.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.annotations;
+
+import fr.zcraft.zlib.components.commands2.CommandRunnable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Subcommand {
+ Class extends CommandRunnable> value();
+ String name() default "";
+ String[] aliases() default {};
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/converters/IntegerTypeConverter.java b/src/main/java/fr/zcraft/zlib/components/commands2/converters/IntegerTypeConverter.java
new file mode 100644
index 00000000..cb22a386
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/converters/IntegerTypeConverter.java
@@ -0,0 +1,20 @@
+package fr.zcraft.zlib.components.commands2.converters;
+
+import fr.zcraft.zlib.components.commands2.ParameterTypeConverter;
+import fr.zcraft.zlib.components.commands2.exceptions.ParameterTypeConverterException;
+
+public class IntegerTypeConverter implements ParameterTypeConverter {
+ @Override
+ public Class getType() {
+ return Integer.class;
+ }
+
+ @Override
+ public Integer fromArgument(String argument) throws ParameterTypeConverterException {
+ try {
+ return Integer.parseInt(argument);
+ } catch(NumberFormatException e) {
+ throw new ParameterTypeConverterException("Invalid integer", e);
+ }
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/converters/URITypeConverter.java b/src/main/java/fr/zcraft/zlib/components/commands2/converters/URITypeConverter.java
new file mode 100644
index 00000000..64cc2710
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/converters/URITypeConverter.java
@@ -0,0 +1,23 @@
+package fr.zcraft.zlib.components.commands2.converters;
+
+import fr.zcraft.zlib.components.commands2.ParameterTypeConverter;
+import fr.zcraft.zlib.components.commands2.exceptions.ParameterTypeConverterException;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public class URITypeConverter implements ParameterTypeConverter {
+ @Override
+ public Class getType() {
+ return URI.class;
+ }
+
+ @Override
+ public URI fromArgument(String argument) throws ParameterTypeConverterException {
+ try {
+ return new URI(argument);
+ } catch (URISyntaxException e) {
+ throw new ParameterTypeConverterException("Invalid URI", e);
+ }
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ArgumentException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ArgumentException.java
new file mode 100644
index 00000000..d5d11760
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ArgumentException.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import java.util.Optional;
+
+public abstract class ArgumentException extends CommandException {
+ private final Optional argument;
+ private Optional argumentPosition;
+
+ public ArgumentException() {
+ this(Optional.empty(), Optional.empty());
+ }
+
+ public ArgumentException(String argument) {
+ this(Optional.of(argument), Optional.empty());
+ }
+
+ public ArgumentException(String argument, int argumentPosition) {
+ this(Optional.of(argument), Optional.of(argumentPosition));
+ }
+
+ public ArgumentException(Optional argument, Optional argumentPosition) {
+ this.argument = argument;
+ this.argumentPosition = argumentPosition;
+ }
+
+ public Optional getArgument() {
+ return argument;
+ }
+
+ public Optional getArgumentPosition() {
+ return argumentPosition;
+ }
+
+ public void setArgumentPosition(Optional argumentPosition) {
+ this.argumentPosition = argumentPosition;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandConfigurationException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandConfigurationException.java
new file mode 100644
index 00000000..d76d7dbd
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandConfigurationException.java
@@ -0,0 +1,19 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+public class CommandConfigurationException extends RuntimeException {
+ private final Class> runnableClass;
+ private final String errorMessage;
+
+ public CommandConfigurationException(Class> runnableClass, String errorMessage) {
+ this.runnableClass = runnableClass;
+ this.errorMessage = errorMessage;
+ }
+
+ public Class> getRunnableClass() {
+ return runnableClass;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandException.java
new file mode 100644
index 00000000..12cff7a0
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+public class CommandException extends Exception
+{
+
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandNotFoundException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandNotFoundException.java
new file mode 100644
index 00000000..04e9e5b7
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/CommandNotFoundException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+public class CommandNotFoundException extends CommandException {
+ private final String commandName;
+
+ public CommandNotFoundException(String commandName) {
+ this.commandName = commandName;
+ }
+
+ public String getCommandName() {
+ return commandName;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ExtraArgumentException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ExtraArgumentException.java
new file mode 100644
index 00000000..5a8fd926
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ExtraArgumentException.java
@@ -0,0 +1,7 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+public class ExtraArgumentException extends ArgumentException {
+ public ExtraArgumentException(String argument, int position) {
+ super(argument, position);
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/FlagAlreadyDefinedException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/FlagAlreadyDefinedException.java
new file mode 100644
index 00000000..d71f8340
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/FlagAlreadyDefinedException.java
@@ -0,0 +1,16 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import fr.zcraft.zlib.components.commands2.Flag;
+
+public class FlagAlreadyDefinedException extends ArgumentException {
+ private final Flag flag;
+
+ public FlagAlreadyDefinedException(Flag flag, String argument, int position) {
+ super(argument, position);
+ this.flag = flag;
+ }
+
+ public Flag getFlag() {
+ return flag;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/FlagMissingValueException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/FlagMissingValueException.java
new file mode 100644
index 00000000..cf8a5d3d
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/FlagMissingValueException.java
@@ -0,0 +1,18 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import fr.zcraft.zlib.components.commands2.Flag;
+
+import java.util.Optional;
+
+public class FlagMissingValueException extends ArgumentException {
+ private final Flag flag;
+
+ public FlagMissingValueException(Flag flag, int position) {
+ super(Optional.empty(), Optional.of(position));
+ this.flag = flag;
+ }
+
+ public Flag getFlag() {
+ return flag;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/InvalidArgumentException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/InvalidArgumentException.java
new file mode 100644
index 00000000..6b56457e
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/InvalidArgumentException.java
@@ -0,0 +1,22 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import java.util.Optional;
+
+public class InvalidArgumentException extends ArgumentException {
+ private final String parseErrorMessage;
+ private final Optional parseErrorCause;
+
+ public InvalidArgumentException(ParameterTypeConverterException sourceException, String argument, int position) {
+ super(argument, position);
+ this.parseErrorMessage = sourceException.getParseErrorMessage();
+ this.parseErrorCause = sourceException.getParseErrorCause();
+ }
+
+ public String getParseErrorMessage() {
+ return parseErrorMessage;
+ }
+
+ public Optional getParseErrorCause() {
+ return parseErrorCause;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingArgumentException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingArgumentException.java
new file mode 100644
index 00000000..db819108
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingArgumentException.java
@@ -0,0 +1,5 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+public class MissingArgumentException extends ArgumentException {
+
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingParameterException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingParameterException.java
new file mode 100644
index 00000000..4f23cf43
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingParameterException.java
@@ -0,0 +1,15 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import fr.zcraft.zlib.components.commands2.Parameter;
+
+public class MissingParameterException extends ArgumentException {
+ private final Parameter flag;
+
+ public MissingParameterException(Parameter flag) {
+ this.flag = flag;
+ }
+
+ public Parameter getFlag() {
+ return flag;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingRequiredFlagException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingRequiredFlagException.java
new file mode 100644
index 00000000..ce5c8bb1
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingRequiredFlagException.java
@@ -0,0 +1,15 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import fr.zcraft.zlib.components.commands2.Flag;
+
+public class MissingRequiredFlagException extends ArgumentException {
+ private final Flag flag;
+
+ public MissingRequiredFlagException(Flag flag) {
+ this.flag = flag;
+ }
+
+ public Flag getFlag() {
+ return flag;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingSubcommandException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingSubcommandException.java
new file mode 100644
index 00000000..23c83b6e
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/MissingSubcommandException.java
@@ -0,0 +1,15 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import fr.zcraft.zlib.components.commands2.Command;
+
+public class MissingSubcommandException extends ArgumentException {
+ private final Command> parentCommand;
+
+ public MissingSubcommandException(Command> parentCommand) {
+ this.parentCommand = parentCommand;
+ }
+
+ public Command> getParentCommand() {
+ return parentCommand;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ParameterTypeConverterException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ParameterTypeConverterException.java
new file mode 100644
index 00000000..7c6e65ea
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/ParameterTypeConverterException.java
@@ -0,0 +1,29 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import java.util.Optional;
+
+public class ParameterTypeConverterException extends Exception {
+ private final String parseErrorMessage;
+ private final Optional cause;
+
+ public ParameterTypeConverterException(String parseErrorMessage) {
+ this(parseErrorMessage, Optional.empty());
+ }
+
+ public ParameterTypeConverterException(String parseErrorMessage, Throwable cause) {
+ this(parseErrorMessage, Optional.of(cause));
+ }
+
+ public ParameterTypeConverterException(String parseErrorMessage, Optional cause) {
+ this.parseErrorMessage = parseErrorMessage;
+ this.cause = cause;
+ }
+
+ public String getParseErrorMessage() {
+ return parseErrorMessage;
+ }
+
+ public Optional getParseErrorCause() {
+ return cause;
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnhandledParameterType.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnhandledParameterType.java
new file mode 100644
index 00000000..075dd8ae
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnhandledParameterType.java
@@ -0,0 +1,27 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import java.lang.reflect.Field;
+
+public class UnhandledParameterType extends CommandConfigurationException {
+ private final Class> type;
+ private final Field field;
+
+ public UnhandledParameterType(Class> type, Field field) {
+ super(field.getDeclaringClass(), "");
+ this.type = type;
+ this.field = field;
+ }
+
+ public Class> getType() {
+ return type;
+ }
+
+ private Field getField() {
+ return field;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Type error in " + field.getDeclaringClass().getName() + "." + field.getName() + " : no parameter type converters found for type " + type.getName();
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnknownFlagException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnknownFlagException.java
new file mode 100644
index 00000000..965acaa5
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnknownFlagException.java
@@ -0,0 +1,7 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+public class UnknownFlagException extends ArgumentException {
+ public UnknownFlagException(String argument, int position) {
+ super(argument, position);
+ }
+}
diff --git a/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnknownSubcommandException.java b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnknownSubcommandException.java
new file mode 100644
index 00000000..a7833360
--- /dev/null
+++ b/src/main/java/fr/zcraft/zlib/components/commands2/exceptions/UnknownSubcommandException.java
@@ -0,0 +1,16 @@
+package fr.zcraft.zlib.components.commands2.exceptions;
+
+import fr.zcraft.zlib.components.commands2.Command;
+
+public class UnknownSubcommandException extends ArgumentException {
+ private final Command> parentCommand;
+
+ public UnknownSubcommandException(Command> parentCommand, String argument, int position) {
+ super(argument, position);
+ this.parentCommand = parentCommand;
+ }
+
+ public Command> getParentCommand() {
+ return parentCommand;
+ }
+}
diff --git a/src/test/java/fr/zcraft/zlib/components/commands2/CommandsTest.java b/src/test/java/fr/zcraft/zlib/components/commands2/CommandsTest.java
new file mode 100644
index 00000000..692fb8fa
--- /dev/null
+++ b/src/test/java/fr/zcraft/zlib/components/commands2/CommandsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2;
+
+import fr.zcraft.zlib.components.commands2.bb.BBCommand;
+import fr.zcraft.zlib.components.commands2.exceptions.CommandException;
+import fr.zcraft.zlib.components.commands2.iom.CreateCommand;
+import fr.zcraft.zlib.components.commands2.iom.IoMCommand;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Optional;
+
+public class CommandsTest
+{
+ static private final CommandSender sender = new CommandSender();
+ @Test
+ public void iomTest() throws CommandException, URISyntaxException {
+ Commands.register(IoMCommand.class, "maptool");
+ Commands.register(CreateCommand.class, "tomap");
+
+ Context> mapToolContext = Commands.makeContext("maptool", sender, new String[]{"list"});
+ Assert.assertEquals(Optional.of(IoMCommand.LIST), mapToolContext.getParentContext().map(Context::getCommandRunnable));
+ Assert.assertTrue(mapToolContext.getCommandRunnable() instanceof IoMCommand.ListCommand);
+
+ Context> createContext = Commands.makeContext("maptool", sender, new String[]{"create", "http://example.com/test.png", "-w", "42", "--stretch"});
+ Assert.assertTrue(createContext.getCommandRunnable() instanceof CreateCommand);
+ CreateCommand createRunnable = (CreateCommand) createContext.getCommandRunnable();
+
+ Assert.assertEquals(new URI("http://example.com/test.png"), createRunnable.imageURI);
+ Assert.assertEquals(Optional.of(42), createRunnable.width);
+ Assert.assertEquals(Optional.empty(), createRunnable.height);
+ Assert.assertEquals(true, createRunnable.stretch);
+ Assert.assertEquals(false, createRunnable.cover);
+
+ }
+
+ @Test
+ public void bbTest() throws CommandException {
+ Commands.registerParameterTypeConverter(new BBCommand.BBItemParamConverter());
+ Commands.register(BBCommand.class, "bb");
+
+ Context> bbContext = Commands.makeContext("bb", sender, new String[]{"saw"});
+ Assert.assertTrue(bbContext.getCommandRunnable() instanceof BBCommand);
+ BBCommand bbRunnable = (BBCommand) bbContext.getCommandRunnable();
+ Assert.assertEquals("saw", bbRunnable.item.itemType);
+ Assert.assertEquals(Optional.empty(), bbRunnable.amount);
+ }
+}
diff --git a/src/test/java/fr/zcraft/zlib/components/commands2/bb/BBCommand.java b/src/test/java/fr/zcraft/zlib/components/commands2/bb/BBCommand.java
new file mode 100644
index 00000000..593d3828
--- /dev/null
+++ b/src/test/java/fr/zcraft/zlib/components/commands2/bb/BBCommand.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright or © or Copr. ZLib contributors (2015 - 2016)
+ *
+ * This software is governed by the CeCILL-B license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-B
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-B license and that you accept its terms.
+ */
+
+package fr.zcraft.zlib.components.commands2.bb;
+
+import fr.zcraft.zlib.components.commands2.CommandRunnable;
+import fr.zcraft.zlib.components.commands2.ParameterTypeConverter;
+import fr.zcraft.zlib.components.commands2.exceptions.ParameterTypeConverterException;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+public class BBCommand implements CommandRunnable {
+ public BBItem item;
+ public Optional amount;
+
+ static public class BBItem {
+ static public final String[] items = {"saw", "stonecutter"};
+ public final String itemType;
+
+ public BBItem(String itemType) {
+ this.itemType = itemType;
+ }
+ }
+
+ static public class BBItemParamConverter implements ParameterTypeConverter {
+ @Override
+ public Class getType() {
+ return BBItem.class;
+ }
+
+ @Override
+ public BBItem fromArgument(String argument) throws ParameterTypeConverterException {
+ argument = argument.toLowerCase();
+ if(!Arrays.asList(BBItem.items).contains(argument)) throw new ParameterTypeConverterException("Invalid item name");
+ return new BBItem(argument);
+ }
+ }
+}
diff --git a/src/test/java/fr/zcraft/zlib/components/commands2/iom/CreateCommand.java b/src/test/java/fr/zcraft/zlib/components/commands2/iom/CreateCommand.java
new file mode 100644
index 00000000..003331e9
--- /dev/null
+++ b/src/test/java/fr/zcraft/zlib/components/commands2/iom/CreateCommand.java
@@ -0,0 +1,35 @@
+package fr.zcraft.zlib.components.commands2.iom;
+
+import fr.zcraft.zlib.components.commands2.CommandRunnable;
+import fr.zcraft.zlib.components.commands2.Context;
+import fr.zcraft.zlib.components.commands2.annotations.About;
+import fr.zcraft.zlib.components.commands2.annotations.Flag;
+
+import java.net.URI;
+import java.util.Optional;
+
+public class CreateCommand implements CommandRunnable {
+
+ @About("The URI")
+ public URI imageURI;
+
+ @About("The width")
+ @Flag(shortName = "w")
+ public Optional width;
+
+ @About("The height")
+ @Flag(shortName = "h")
+ public Optional height;
+
+ @Flag
+ public boolean stretch;
+
+ @Flag
+ public boolean cover;
+
+ @Override
+ public void run(Context context) {
+ System.out.println("Hello world !");
+ }
+
+}
diff --git a/src/test/java/fr/zcraft/zlib/components/commands2/iom/IoMCommand.java b/src/test/java/fr/zcraft/zlib/components/commands2/iom/IoMCommand.java
new file mode 100644
index 00000000..de6d592e
--- /dev/null
+++ b/src/test/java/fr/zcraft/zlib/components/commands2/iom/IoMCommand.java
@@ -0,0 +1,22 @@
+package fr.zcraft.zlib.components.commands2.iom;
+
+import fr.zcraft.zlib.components.commands2.exceptions.CommandException;
+import fr.zcraft.zlib.components.commands2.CommandRunnable;
+import fr.zcraft.zlib.components.commands2.Context;
+import fr.zcraft.zlib.components.commands2.annotations.Subcommand;
+
+public enum IoMCommand implements CommandRunnable {
+ @Subcommand(CreateCommand.class)
+ CREATE,
+ @Subcommand(ListCommand.class)
+ LIST,
+ ;
+
+ static public class ListCommand implements CommandRunnable {
+
+ @Override
+ public void run(Context context) throws CommandException {
+
+ }
+ }
+}
diff --git a/src/test/resources/help/belovedblocks.fr_FR.txt b/src/test/resources/help/belovedblocks.fr_FR.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks.fr_FR.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks.txt b/src/test/resources/help/belovedblocks.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks/give.fr_FR.txt b/src/test/resources/help/belovedblocks/give.fr_FR.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks/give.fr_FR.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks/give.txt b/src/test/resources/help/belovedblocks/give.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks/give.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks/give/block.fr_FR.txt b/src/test/resources/help/belovedblocks/give/block.fr_FR.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks/give/block.fr_FR.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks/give/block.txt b/src/test/resources/help/belovedblocks/give/block.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks/give/block.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks/give/tool.fr_FR.txt b/src/test/resources/help/belovedblocks/give/tool.fr_FR.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks/give/tool.fr_FR.txt
@@ -0,0 +1 @@
+
diff --git a/src/test/resources/help/belovedblocks/give/tool.txt b/src/test/resources/help/belovedblocks/give/tool.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/src/test/resources/help/belovedblocks/give/tool.txt
@@ -0,0 +1 @@
+