diff --git a/aesh/src/main/java/org/aesh/AeshConsoleRunner.java b/aesh/src/main/java/org/aesh/AeshConsoleRunner.java
index 2b045dff..efa3067d 100644
--- a/aesh/src/main/java/org/aesh/AeshConsoleRunner.java
+++ b/aesh/src/main/java/org/aesh/AeshConsoleRunner.java
@@ -24,6 +24,7 @@
import org.aesh.command.CommandResult;
import org.aesh.command.impl.registry.AeshCommandRegistryBuilder;
import org.aesh.command.invocation.CommandInvocation;
+import org.aesh.command.registry.CommandRegistry;
import org.aesh.command.registry.CommandRegistryException;
import org.aesh.command.settings.Settings;
import org.aesh.command.settings.SettingsBuilder;
@@ -32,9 +33,6 @@
import org.aesh.terminal.Connection;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
/**
* Use the AeshConsoleRunner when you want to easily create an interactive CLI application.
@@ -42,14 +40,13 @@
* @author Ståle Pedersen
*/
public class AeshConsoleRunner {
- private List> commands;
+ private AeshCommandRegistryBuilder registryBuilder;
private Settings settings;
private Prompt prompt;
private ReadlineConsole console;
private Connection connection;
private AeshConsoleRunner() {
- commands = new ArrayList<>();
}
public static AeshConsoleRunner builder() {
@@ -57,23 +54,46 @@ public static AeshConsoleRunner builder() {
}
public AeshConsoleRunner commands(Class extends Command>... commands) {
- if(commands != null)
- this.commands.addAll(Arrays.asList(commands));
+ if(commands != null) {
+ ensureRegistryBuilderInitialized();
+ try {
+ registryBuilder.commands(commands);
+ } catch (CommandRegistryException e) {
+ throw new RuntimeException("Error when adding commands: " + e.getMessage(), e);
+ }
+ }
return this;
}
- public AeshConsoleRunner command(Class extends Command> commands) {
- if(commands != null)
- this.commands.add(commands);
+ public AeshConsoleRunner command(Class extends Command> command) {
+ if(command != null) {
+ ensureRegistryBuilderInitialized();
+ try {
+ registryBuilder.command(command);
+ } catch (CommandRegistryException e) {
+ throw new RuntimeException("Error when adding command: " + e.getMessage(), e);
+ }
+ }
return this;
}
- public AeshConsoleRunner commands(List> commands) {
- if(commands != null)
- this.commands.addAll(commands);
+ public AeshConsoleRunner commandRegistryBuilder(AeshCommandRegistryBuilder commandRegistryBuilder) {
+ if(registryBuilder != null) {
+ throw new RuntimeException("Cannot set CommandRegistryBuilder after it has been initialized. " +
+ "CommandRegistryBuilder must be set before adding any commands.");
+ }
+ if(commandRegistryBuilder != null) {
+ this.registryBuilder = commandRegistryBuilder;
+ }
return this;
}
+ private void ensureRegistryBuilderInitialized() {
+ if(registryBuilder == null) {
+ registryBuilder = AeshCommandRegistryBuilder.builder();
+ }
+ }
+
public AeshConsoleRunner settings(Settings settings) {
if(settings != null)
this.settings = settings;
@@ -102,7 +122,12 @@ public AeshConsoleRunner prompt(Prompt prompt) {
}
public AeshConsoleRunner addExitCommand() {
- commands.add(ExitCommand.class);
+ ensureRegistryBuilderInitialized();
+ try {
+ registryBuilder.command(ExitCommand.class);
+ } catch (CommandRegistryException e) {
+ throw new RuntimeException("Error when adding exit command: " + e.getMessage(), e);
+ }
return this;
}
@@ -127,18 +152,42 @@ public void stop() {
@SuppressWarnings("unchecked")
private void init() {
- if(commands.isEmpty() && (settings == null ||
- settings.commandRegistry() == null ||
- settings.commandRegistry().getAllCommandNames().isEmpty()))
+ // Build the command registry from the builder
+ CommandRegistry builtRegistry = null;
+ if(registryBuilder != null) {
+ try {
+ builtRegistry = registryBuilder.create();
+ } catch (Exception e) {
+ throw new RuntimeException("Error creating command registry: " + e.getMessage(), e);
+ }
+ }
+
+ // Check if both builder and settings.commandRegistry have commands
+ if(builtRegistry != null && !builtRegistry.getAllCommandNames().isEmpty() &&
+ settings != null && settings.commandRegistry() != null &&
+ !settings.commandRegistry().getAllCommandNames().isEmpty()) {
+ throw new RuntimeException("Cannot define commands in both AeshConsoleRunner (via command() or commandRegistryBuilder()) " +
+ "and Settings.commandRegistry(). Please use only one method to specify commands.");
+ }
+
+ // Determine which registry to use
+ CommandRegistry finalRegistry = null;
+ if(builtRegistry != null && !builtRegistry.getAllCommandNames().isEmpty()) {
+ finalRegistry = builtRegistry;
+ } else if(settings != null && settings.commandRegistry() != null &&
+ !settings.commandRegistry().getAllCommandNames().isEmpty()) {
+ finalRegistry = settings.commandRegistry();
+ }
+
+ // Validate that we have at least one command
+ if(finalRegistry == null || finalRegistry.getAllCommandNames().isEmpty()) {
throw new RuntimeException("No commands added, nothing to run");
+ }
try {
if(settings == null) {
- AeshCommandRegistryBuilder registryBuilder = AeshCommandRegistryBuilder.builder();
- for(Class extends Command> command : commands)
- registryBuilder.command(command);
settings = SettingsBuilder.builder()
- .commandRegistry(registryBuilder.create())
+ .commandRegistry(finalRegistry)
.enableAlias(false)
.enableExport(false)
.enableMan(false)
@@ -146,16 +195,11 @@ private void init() {
.connection(connection)
.build();
}
- //user added its own settings object, but no commands in registry
- else if(!commands.isEmpty() &&
- (settings.commandRegistry() == null ||
- settings.commandRegistry().getAllCommandNames().isEmpty())) {
-
- AeshCommandRegistryBuilder registryBuilder = AeshCommandRegistryBuilder.builder();
- for(Class extends Command> command : commands)
- registryBuilder.command(command);
+ // User added their own settings object, but we need to add or replace the registry
+ else if(settings.commandRegistry() == null ||
+ settings.commandRegistry().getAllCommandNames().isEmpty()) {
SettingsBuilder settingsBuilder = new SettingsBuilder(settings)
- .commandRegistry(registryBuilder.create());
+ .commandRegistry(finalRegistry);
if(connection != null)
settingsBuilder.connection(connection);
@@ -165,8 +209,8 @@ else if(!commands.isEmpty() &&
console = new ReadlineConsole(settings);
}
- catch (CommandRegistryException e) {
- throw new RuntimeException("Error when adding command: "+e.getMessage());
+ catch (Exception e) {
+ throw new RuntimeException("Error when initializing console: " + e.getMessage(), e);
}
}
diff --git a/aesh/src/test/java/org/aesh/AeshConsoleRunnerTest.java b/aesh/src/test/java/org/aesh/AeshConsoleRunnerTest.java
index 81f37768..051e4c95 100644
--- a/aesh/src/test/java/org/aesh/AeshConsoleRunnerTest.java
+++ b/aesh/src/test/java/org/aesh/AeshConsoleRunnerTest.java
@@ -103,6 +103,88 @@ public void testMultipleCommands() throws InterruptedException {
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testCommandRegistryDirect() throws Exception {
+ TestConnection connection = new TestConnection();
+
+ AeshCommandRegistryBuilder builder = AeshCommandRegistryBuilder.builder()
+ .command(HelloCommand.class)
+ .command(AeshConsoleRunner.ExitCommand.class);
+
+ AeshConsoleRunner runner = AeshConsoleRunner.builder()
+ .connection(connection)
+ .commandRegistryBuilder(builder);
+
+ runner.start();
+
+ connection.read("hello"+getLineSeparator());
+ connection.assertBufferEndsWith("Hello from Aesh!"+getLineSeparator());
+ connection.read("exit"+getLineSeparator());
+ Thread.sleep(200);
+ assertTrue(connection.closed());
+ }
+
+ @Test(expected = RuntimeException.class)
+ @SuppressWarnings("unchecked")
+ public void testDuplicateCommandRegistry() throws Exception {
+ TestConnection connection = new TestConnection();
+
+ CommandRegistry registry = AeshCommandRegistryBuilder.builder()
+ .command(HelloCommand.class)
+ .create();
+
+ Settings
+ settings = SettingsBuilder.builder()
+ .logging(true)
+ .connection(connection)
+ .commandRegistry(registry)
+ .build();
+
+ // This should throw an exception because we're defining commands in both places
+ AeshConsoleRunner runner = AeshConsoleRunner.builder()
+ .settings(settings)
+ .command(Bar1Command.class); // Adding command when settings already has a non-empty registry
+
+ runner.start();
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testCommandRegistryBuilder() throws Exception {
+ TestConnection connection = new TestConnection();
+
+ AeshCommandRegistryBuilder builder = AeshCommandRegistryBuilder.builder()
+ .command(HelloCommand.class);
+
+ AeshConsoleRunner runner = AeshConsoleRunner.builder()
+ .connection(connection)
+ .commandRegistryBuilder(builder)
+ .addExitCommand();
+
+ runner.start();
+
+ connection.read("hello"+getLineSeparator());
+ connection.assertBufferEndsWith("Hello from Aesh!"+getLineSeparator());
+ connection.read("exit"+getLineSeparator());
+ Thread.sleep(200);
+ assertTrue(connection.closed());
+ }
+
+ @Test(expected = RuntimeException.class)
+ @SuppressWarnings("unchecked")
+ public void testCommandRegistryBuilderAfterInit() {
+ AeshCommandRegistryBuilder builder = AeshCommandRegistryBuilder.builder();
+
+ // Add a command first, which initializes the default builder
+ AeshConsoleRunner runner = AeshConsoleRunner.builder()
+ .command(HelloCommand.class);
+
+ // This should throw an exception because the builder was already initialized
+ runner.commandRegistryBuilder(builder);
+ }
+
@CommandDefinition(name = "hello", description = "hello from aesh")
public static class HelloCommand implements Command {
diff --git a/examples/dependency-reduced-pom.xml b/examples/dependency-reduced-pom.xml
index 69898a87..6b621e61 100644
--- a/examples/dependency-reduced-pom.xml
+++ b/examples/dependency-reduced-pom.xml
@@ -3,7 +3,7 @@
aesh-all
org.aesh
- 2.8.4
+ 3.0-dev
4.0.0
aesh-examples