https://github.com/k-boyle/oktane
A high performance Java command framework
https://github.com/k-boyle/oktane
hacktoberfest hacktoberfest2021 java performance
Last synced: about 1 year ago
JSON representation
A high performance Java command framework
- Host: GitHub
- URL: https://github.com/k-boyle/oktane
- Owner: k-boyle
- License: gpl-3.0
- Created: 2021-02-02T17:41:56.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2025-06-10T12:11:10.000Z (about 1 year ago)
- Last Synced: 2025-06-23T09:13:19.174Z (about 1 year ago)
- Topics: hacktoberfest, hacktoberfest2021, java, performance
- Language: Java
- Homepage:
- Size: 6 MB
- Stars: 9
- Watchers: 1
- Forks: 0
- Open Issues: 11
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://sonarcloud.io/dashboard?id=k-boyle_Oktane)
[](https://search.maven.org/artifact/com.github.k-boyle/Oktane)
[](https://oss.sonatype.org/#nexus-search;quick~oktane)
Oktane is a high performance, highly configurable Java command framework used to map strings to methods, and execute them.
It is built upon the [Reactor](https://projectreactor.io/) framework to allow easy integration with reactive projects, such as [Discord4J](https://github.com/Discord4J/Discord4J).
Inspired by [Qmmands](https://github.com/quahu/qmmands).
Guides can be found on the [Wiki](https://github.com/k-boyle/Oktane/wiki), Javadocs on [gh-pages](https://k-boyle.github.io/Oktane/), example usage can be seen in the OktaneExample module, and an example using Discord4J and Spring [here](https://github.com/k-boyle/degenerate).
# Usage #
**Context Creation**
Your command context is a standard pojo used to pass contextual data into your commands. `BeanProvider` is a service container with the interface providing a default implementations.
```java
public class OktaneCommandContext extends CommandContext {
private final String user;
public OktaneCommandContext(String user, BeanProvider beanProvider) {
super(beanProvider);
this.user = user;
}
public String user() {
return user;
}
}
```
**Module Creation**
To define a class as a module the class just needs to extend `ModuleBase`.
The `@Aliases` annotation is used to force an annotation processor to run.
Methods that are **public** and return `CommandResult` or `Mono` are designated as commands.
When a class extends `ModuleBase` a class will be generated that corresponds to each command method which will be used to invoke the commands at runtime,
this approach means that there is no overhead vs a direct method call,
if the module is not annotated then reflection will be used to invoke the methods (this is some magnitudes slower).
The `Aliases` annotation tells the `CommandHandler` what strings to map to this method.
```java
public class OktaneCommandModule extends ModuleBase {
@Aliases({"echo", "e"})
public CommandResult pingPong(@Remainder String input) {
return message(context().user() + " said: " + input);
}
@Aliases({"ping", "p"})
public Mono ping() {
return sendWebRequest()
.map(statusCode -> message("Got response: " + statusCode));
}
}
```
**CommandHandler Creation**
The command handler is your interface for interacting with your commands.
```java
public CommandHandler commandHandler() {
return CommandHandler.builder()
.withModule(OktaneCommandModule.class)
.build();
}
```
**Command Invocation**
To invoke a command you simply call to call `excute` on the command handler, pass it your command context, and the string input to parse.
```java
OktaneCommandContext context = new OktaneCommandContext("Kieran", BeanProvider.get());
Mono result = commandHandlder.execute("echo Oktane is really cool :)", context);
result.ofType(CommandMessageResult.class)
.map(CommandMessageResult::message)
.subscribe(message -> System.out.println(message));
```
**Granular Configuration**
Modules and commands can be configured a fair amount.
```java
@Name("My Module") // Can be used in help displays, all the modules and commands can be accessed via
// CommandHandler#modules, and CommandHandler#commands
@Description("This is a command module") // Can be used in help displays
@Aliases({"a", "b"}) // commands inside a group must have the group prefix to execute, e.g. "a echo"
@Singleton // Makes the module a singleton (transient by default)
@Synchronised // Makes it so that all commands in the module are synchronised on a shared lock
public class OktaneCommandModule extends ModuleBase {
@Name("Echo Command") // Can be used in help displays
@Description("Echos input") // Can be used in help displays
@Aliases({"echo", "e"}) // Defines the different aliases that can invoke the command
@Synchronised // Makes it so that the command is locally synchronised (public CommandResult synchronised ...)
public CommandResult pingPong(
@Name("User Input") // Can be used in help displays
@Description("The input to echo") // Can be used in help displays
@Remainder // Denotes the parameter as a remainder, so all the remaining text left to parse
// will be passed into this parameter. There can only be one remainder, and it
// must be the last parameter
String input) {
return message(context().user() + " said: " + input);
}
}
```
**Type Parsing**
Oktane supports parsing all the primitive types, see `PrimitiveTypeParserFactory`, and allowing a user to define their own.
Type parsers are added during the `CommandHandler` building stage using the `withTypeParser` method.
```java
public class UserTypeParser implements TypeParser {
@Override
public Mono> parse(CommandContext context, Command command, String input) {
return context.beanProvider().get(UserService.class)
.getUser(input)
.map(this::success)
.switchOnEmpty(failure("Failed to parse %s as a valid user", input).mono());
}
}
```
**Dependency Injection**
Beans can be injected into module using the `BeanProvider`, any constructor arguments will be passed into the module on instantiation, the `CommandHandler`
will inject itself and does not need to be added to a provider.
```java
public class OktaneCommandModule extends ModuleBase {
private final CommandHandler commandHandler;
private final UserService userService;
public OktaneCommandModule(
CommandHandler commandHandler,
UserService userService) {
this.commandHandler = commandHandler;
this.userService = userService;
}
@Aliases({"commands", "c"})
public CommandResult commandCount() {
return message("There are " + commandHandler.commands().count() + " commands");
}
@Aliases({"users"})
public Mono listUsers() {
return userService.getAll()
.map(users -> message(users));
}
}
```