This repository has been archived on 2021-12-05. You can view files and clone it, but cannot push or open issues or pull requests.
envoy/client/src/main/java/envoy/client/data/commands/SystemCommandsMap.java

160 lines
6.3 KiB
Java
Raw Normal View History

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)-> &lt;Button&gt;.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; }
}