Revised SystemCommand mechanism and implemented theoretical execution
This commit is contained in:
parent
ce3a4a8979
commit
d2303a187d
@ -1,26 +0,0 @@
|
|||||||
package envoy.client.data.commands;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the base class for all {@link SystemCommand}s that do not need
|
|
||||||
* another argument to parse their function.
|
|
||||||
* <p>
|
|
||||||
* Project: <strong>envoy-client</strong><br>
|
|
||||||
* File: <strong>NoArgSystemCommand.java</strong><br>
|
|
||||||
* Created: <strong>16.07.2020</strong><br>
|
|
||||||
*
|
|
||||||
* @author Leon Hofmeister
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public class NoArgSystemCommand extends SystemCommand<Void> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new {@code NoArgSystemCommand} that takes no arguments.
|
|
||||||
*
|
|
||||||
* @param command the string that must be inputted to execute the given action
|
|
||||||
* @param action the action that should be performed
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public NoArgSystemCommand(String command, Function<Void, Void> action) { super(command, action); }
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package envoy.client.data.commands;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the base class for all {@link SystemCommand}s that need a
|
|
||||||
* String to parse their function.
|
|
||||||
* <p>
|
|
||||||
* Project: <strong>envoy-client</strong><br>
|
|
||||||
* File: <strong>StringArgSystemCommand.java</strong><br>
|
|
||||||
* Created: <strong>16.07.2020</strong><br>
|
|
||||||
*
|
|
||||||
* @author Leon Hofmeister
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public class StringArgSystemCommand extends SystemCommand<String> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new {@code NoArgSystemCommand} that takes a String argument.
|
|
||||||
*
|
|
||||||
* @param command the string that must be inputted to execute the given action
|
|
||||||
* @param action the action that should be performed
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public StringArgSystemCommand(String command, Function<String, Void> action) { super(command, action); }
|
|
||||||
}
|
|
@ -4,48 +4,62 @@ import java.util.function.Function;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is the base class of all {@code SystemCommands} and contains an
|
* This class is the base class of all {@code SystemCommands} and contains an
|
||||||
* action and a command that needs to be inputted to execute the given action.
|
* action and a number of arguments that should be used as input for this
|
||||||
|
* function.
|
||||||
* No {@code SystemCommand} can return anything.
|
* No {@code SystemCommand} can return anything.
|
||||||
|
* Every {@code SystemCommand} must have as argument type {@code String[]} so
|
||||||
|
* that the words following the indicator String can be used as input of the
|
||||||
|
* function. This approach has one limitation:<br>
|
||||||
|
* <b>Order matters!</b> Changing the order of arguments will likely result in
|
||||||
|
* unexpected behavior.
|
||||||
* <p>
|
* <p>
|
||||||
* Project: <strong>envoy-client</strong><br>
|
* Project: <strong>envoy-client</strong><br>
|
||||||
* File: <strong>SystemCommand.java</strong><br>
|
* File: <strong>SystemCommand.java</strong><br>
|
||||||
* Created: <strong>16.07.2020</strong><br>
|
* Created: <strong>16.07.2020</strong><br>
|
||||||
*
|
*
|
||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
* @param <T> the type of argument needed
|
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public abstract class SystemCommand<T> {
|
public final class SystemCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This variable stores the command that should be inputted to execute the given
|
* This variable stores the amount of arguments that need to be parsed for the
|
||||||
* action
|
* underlying function.
|
||||||
*/
|
*/
|
||||||
protected final String command;
|
protected final int numberOfArguments;
|
||||||
|
|
||||||
protected final Function<T, Void> action;
|
/**
|
||||||
|
* This Function takes a {@code String[]} as argument because automatically
|
||||||
|
* {@code SystemCommand#numberOfArguments} words following the necessary command
|
||||||
|
* will be put into this array.
|
||||||
|
*
|
||||||
|
* @see String#split(String)
|
||||||
|
*/
|
||||||
|
protected final Function<String[], Void> action;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code NoArgSystemCommand} that takes no arguments.
|
* Constructs a new {@code NoArgSystemCommand} that takes no arguments.
|
||||||
*
|
*
|
||||||
* @param command the string that must be inputted to execute the given action
|
|
||||||
* @param action the action that should be performed
|
* @param action the action that should be performed
|
||||||
|
* @param numberOfArguments the amount of arguments that need to be parsed for
|
||||||
|
* the underlying function
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public SystemCommand(String command, Function<T, Void> action) {
|
public SystemCommand(Function<String[], Void> action, int numberOfArguments) {
|
||||||
this.command = command;
|
this.numberOfArguments = numberOfArguments;
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the command that must be inputted to execute the given action
|
|
||||||
* @since Envoy Client v0.1-beta
|
|
||||||
*/
|
|
||||||
public String getCommand() { return command; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the action that should be performed
|
* @return the action that should be performed
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public Function<T, Void> getAction() { return action; }
|
public Function<String[], Void> getAction() { return action; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the amount of arguments that need to be parsed for
|
||||||
|
* the underlying function
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public int getNumberOfArguments() { return numberOfArguments; }
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,159 @@
|
|||||||
|
package envoy.client.data.commands;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import envoy.util.EnvoyLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class stores all {@link SystemCommand}s used.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>SystemCommandsMap.java</strong><br>
|
||||||
|
* Created: <strong>17.07.2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
* @apiNote Please refrain from using the "/"-char in keys of this map.
|
||||||
|
* Unexpected behavior will occur.
|
||||||
|
*/
|
||||||
|
public class SystemCommandsMap {
|
||||||
|
|
||||||
|
private final HashMap<String, SystemCommand> systemCommands = new HashMap<>();
|
||||||
|
private boolean rethrowFailure = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param command the string that must be inputted to execute the
|
||||||
|
* given action
|
||||||
|
* @param action the action that should be performed
|
||||||
|
* @param numberOfArguments the amount of arguments that need to be parsed for
|
||||||
|
* the underlying function
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public void addCommand(String command, Function<String[], Void> action, int numberOfArguments) {
|
||||||
|
systemCommands.put(command, new SystemCommand(action, numberOfArguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new {@link SystemCommand} to the map that does not depend upon
|
||||||
|
* arguments in the given String
|
||||||
|
*
|
||||||
|
* @param command the string that must be inputted to execute the given action
|
||||||
|
* @param action the action that should be performed. To see why this Function
|
||||||
|
* takes a {@code String[]}, see {@link SystemCommand}
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public void addNoArgCommand(String command, Function<String[], Void> action) { addCommand(command, action, 0); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param command the string that must be inputted to execute the
|
||||||
|
* given action
|
||||||
|
* @param action the action that should be performed. To see why this
|
||||||
|
* Function takes a {@code String[]}, see
|
||||||
|
* {@link SystemCommand}
|
||||||
|
* @param numberOfArguments the amount of arguments that need to be parsed for
|
||||||
|
* the underlying function
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public void add(String command, Function<String[], Void> action, int numberOfArguments) {
|
||||||
|
systemCommands.put(command, new SystemCommand(action, numberOfArguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if the input String is a key in the map and returns the
|
||||||
|
* wrapped System command if present.
|
||||||
|
* Its intended usage is after a "/" has been detected in the input String.
|
||||||
|
* It will return an empty optional if the value after the slash is not a key in
|
||||||
|
* the map, which is a valid case (i.e. input="3/4" and "4" is not a key in the
|
||||||
|
* map).
|
||||||
|
* <p>
|
||||||
|
* Usage example:<br>
|
||||||
|
* {@code SystemCommandsMap systemCommands = new SystemCommandsMap();}<br>
|
||||||
|
* {@code systemCommands.add("example", Function.identity, 1);}<br>
|
||||||
|
* {@code ....}<br>
|
||||||
|
* user input: {@code "/example xyz ..."}<br>
|
||||||
|
* {@code systemCommands.checkPresent("example xyz ...")}
|
||||||
|
* result: {@code SystemCommand[action=Function.identity, numberOfArguments=1]}
|
||||||
|
*
|
||||||
|
* @param input the input string given by the user, <b>excluding the "/"</b>
|
||||||
|
* @return the wrapped system command, if present
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public Optional<SystemCommand> checkPresent(String input) {
|
||||||
|
// TODO: Is String.indexOf inclusive or exclusive?
|
||||||
|
final var firstWord = input.substring(0, input.indexOf(" "));
|
||||||
|
return Optional.ofNullable(systemCommands.get(firstWord));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if the input String is a key in the map and executes the
|
||||||
|
* wrapped System command if present.
|
||||||
|
* Its intended usage is after a "/" has been detected in the input String.
|
||||||
|
* It will do nothing if the value after the slash is not a key in
|
||||||
|
* the map, which is a valid case (i.e. input="3/4" and "4" is not a key in the
|
||||||
|
* map).
|
||||||
|
* <p>
|
||||||
|
* Usage example:<br>
|
||||||
|
* {@code SystemCommandsMap systemCommands = new SystemCommandsMap();}<br>
|
||||||
|
* {@code systemCommands.add("example", (words)-> <Button>.setText(words[0]), 1);}<br>
|
||||||
|
* {@code ....}<br>
|
||||||
|
* user input: {@code "/example xyz ..."}<br>
|
||||||
|
* {@code systemCommands.executeIfPresent("example xyz ...")}
|
||||||
|
* result: {@code <Button>.getText()=="xyz"}
|
||||||
|
*
|
||||||
|
* @param input the input string given by the user, <b>excluding the "/"</b>
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public void executeIfPresent(String input) {
|
||||||
|
checkPresent(input).ifPresent(systemCommand -> {
|
||||||
|
// Splitting the String so that the leading command including the first " " is
|
||||||
|
// removed and only as many following words as allowed by the system command
|
||||||
|
// persist
|
||||||
|
// TODO: Is String.indexOf inclusive or exclusive?
|
||||||
|
final var remainingString = input.substring(input.indexOf(" ") + 1);
|
||||||
|
// TODO: Is Arrays.copyOfRange inclusive or exclusive in the "to" parameter?
|
||||||
|
// TODO: Current implementation will fail in certain cases, i.e. two characters
|
||||||
|
// behind each other (" "), not enough words, ...
|
||||||
|
// TODO: Another way of failure is the fact that in the current implementation,
|
||||||
|
// it is assumed that a String is already present in finished form and not that
|
||||||
|
// it will be finished later on, or does it?
|
||||||
|
final var arguments = Arrays.copyOfRange(remainingString.split(" "), 0, systemCommand.getNumberOfArguments());
|
||||||
|
// Executing the function
|
||||||
|
try {
|
||||||
|
systemCommand.getAction().apply(arguments);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
EnvoyLog.getLogger(SystemCommandsMap.class).log(Level.WARNING, "The system command " +
|
||||||
|
// detected command
|
||||||
|
input.substring(0, input.indexOf(" ")) + " threw an exception: ", e);
|
||||||
|
if (rethrowFailure) throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether failures of {@link SystemCommand}s should be rethrown
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public boolean isRethrowFailure() { return rethrowFailure; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rethrowFailure whether failures of {@link SystemCommand}s should be
|
||||||
|
* rethrown
|
||||||
|
* @return this instance of a {@code SystemCommandsMap}
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public SystemCommandsMap setRethrowFailure(boolean rethrowFailure) {
|
||||||
|
this.rethrowFailure = rethrowFailure;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the systemCommands
|
||||||
|
* @since Envoy Client v0.1-beta
|
||||||
|
*/
|
||||||
|
public HashMap<String, SystemCommand> getSystemCommands() { return systemCommands; }
|
||||||
|
}
|
Reference in New Issue
Block a user