fr.bigeon
diff --git a/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ThreadedServerConsoleManager.java b/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ThreadedServerConsoleManager.java
index 3297dac..aa9dcef 100644
--- a/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ThreadedServerConsoleManager.java
+++ b/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ThreadedServerConsoleManager.java
@@ -71,6 +71,10 @@ public class ThreadedServerConsoleManager implements ConsoleManager {
private BufferedReader input;
/** the prompting status */
private boolean doPrompt;
+ /**
+ *
+ */
+ private boolean closed = false;
/** Create the console manager.
*
@@ -159,6 +163,14 @@ public class ThreadedServerConsoleManager implements ConsoleManager {
@Override
public void close() throws IOException {
// Do nothing
+ this.closed = true;
+ }
+
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
+ @Override
+ public boolean isClosed() {
+ return closed;
}
}
diff --git a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleRunnableTest.java b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleRunnableTest.java
index 0208d98..af4fa31 100644
--- a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleRunnableTest.java
+++ b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleRunnableTest.java
@@ -116,6 +116,13 @@ public class ConsoleRunnableTest {
public void close() throws IOException {
// do nothing
}
+
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
+ @Override
+ public boolean isClosed() {
+ return i == cmds.length;
+ }
}
/** Test method for
@@ -136,7 +143,7 @@ public class ConsoleRunnableTest {
Object lock = new Object();
ConsoleApplication app = new ConsoleTestApplication(
new ConsoleManagerTestImplementation(
- new String[] {"test", ConsoleTestApplication.EXIT}));
+ new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
Thread th = new Thread(runnable);
@@ -151,7 +158,7 @@ public class ConsoleRunnableTest {
Object lock = new Object();
ConsoleApplication app = new ConsoleTestApplication(
new ConsoleManagerTestImplementation(
- new String[] {"test", ConsoleTestApplication.EXIT}));
+ new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
runnable.stop();
Thread th = new Thread(runnable);
@@ -166,7 +173,7 @@ public class ConsoleRunnableTest {
Object lock = new Object();
ConsoleApplication app = new ConsoleTestApplication(
new ConsoleManagerTestImplementation(
- new String[] {"test", ConsoleTestApplication.EXIT}));
+ new String[] {"test", ConsoleTestApplication.EXIT})); //$NON-NLS-1$
ConsoleRunnable runnable = new ConsoleRunnable(app, lock);
runnable.run();
}
diff --git a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleTestApplication.java b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleTestApplication.java
index 202cbf0..c6ea6bf 100644
--- a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleTestApplication.java
+++ b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleTestApplication.java
@@ -34,12 +34,15 @@
*/
package fr.bigeon.gclc.socket;
+import java.io.IOException;
+
import fr.bigeon.gclc.ConsoleApplication;
import fr.bigeon.gclc.command.Command;
-import fr.bigeon.gclc.command.ICommand;
+import fr.bigeon.gclc.command.ExitCommand;
+import fr.bigeon.gclc.command.HelpExecutor;
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.exception.InvalidCommandName;
import fr.bigeon.gclc.manager.ConsoleManager;
-import fr.bigeon.gclc.prompt.CLIPrompterMessages;
/** A test-purpose application
*
@@ -56,7 +59,7 @@ public class ConsoleTestApplication extends ConsoleApplication {
"See you");
try {
add(new ExitCommand(EXIT, this));
- addHelpCommand("help");
+ add(new HelpExecutor("help", manager, this.getRoot()));
add(new Command("test") {
@Override
@@ -65,63 +68,16 @@ public class ConsoleTestApplication extends ConsoleApplication {
}
@Override
- public void execute(String... args) {
- manager.println("Test command ran fine");
+ public void execute(String... args) throws CommandRunException {
+ try {
+ manager.println("Test command ran fine");
+ } catch (IOException e) {
+ throw new CommandRunException("manager closed", e);
+ }
}
});
} catch (final InvalidCommandName e) {
e.printStackTrace();
}
}
-
- /**
- * A command to exit a {@link ConsoleApplication}.
- *
- * @author Emmanuel BIGEON */
- class ExitCommand implements ICommand {
- /** The exit command manual message key */
- private static final String EXIT_MAN = "exit.man"; //$NON-NLS-1$
- /** The tip of the exit command */
- private static final String EXIT_TIP = "exit.tip"; //$NON-NLS-1$
- /** The application that will be exited when this command runs */
- private final ConsoleApplication app;
- /** The exit command name */
- private final String name;
-
- /** @param name the name of the command
- * @param app the application to exit */
- public ExitCommand(String name, ConsoleApplication app) {
- this.name = name;
- this.app = app;
- }
-
- /** The actions to take before exiting */
- public void beforeExit() {
- // Do nothing by default
- }
-
- @Override
- public final void execute(String... args) {
- beforeExit();
- app.exit();
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.command.ICommand#getCommandName() */
- @Override
- public String getCommandName() {
- return name;
- }
-
- @Override
- public void help(ConsoleManager helpManager, String... args) {
- helpManager.println(
- CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
- }
-
- @Override
- public String tip() {
- return CLIPrompterMessages.getString(EXIT_TIP);
- }
- }
}
diff --git a/gclc-swt/pom.xml b/gclc-swt/pom.xml
index 2b1b9ed..1d6c158 100644
--- a/gclc-swt/pom.xml
+++ b/gclc-swt/pom.xml
@@ -51,13 +51,18 @@
fr.bigeon
gclc
- 1.1.2
+ 1.2.0-SNAPSHOT
- org.eclipse.swt.gtk.linux
- x86_64
- 3.3.0-v3346
+ org.eclipse.swt
+ org.eclipse.swt.gtk.linux.x86_64
+ 4.3
+
+ org.eclipse.swt
+ org.eclipse.swt.win32.win32.x86_64
+ 4.3
+
fr.bigeon
collections
diff --git a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsole.java b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsole.java
index 6d57cc0..6b2c692 100644
--- a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsole.java
+++ b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsole.java
@@ -100,9 +100,9 @@ public class SWTConsole extends Composite implements ConsoleManager {
if (e.keyCode == SWT.ARROW_UP &&
currentIndex < commands.size() - 1) {
currentIndex++;
- consoleInput.setText(
- commands.get(commands.size() - currentIndex - 1));
- consoleInput.setSelection(consoleInput.getText().length());
+ String cmd = commands.get(commands.size() - currentIndex - 1);
+ consoleInput.setText(cmd);
+ consoleInput.setSelection(cmd.length());
}
// Lower arrow retrieves next commands
@@ -111,9 +111,10 @@ public class SWTConsole extends Composite implements ConsoleManager {
currentIndex--;
consoleInput.setText(new String());
} else if (currentIndex > 0) {
- consoleInput.setText(commands
- .get(commands.size() - (--currentIndex) - 1));
- consoleInput.setSelection(consoleInput.getText().length());
+ String cmd = commands
+ .get(commands.size() - (--currentIndex) - 1);
+ consoleInput.setText(cmd);
+ consoleInput.setSelection(cmd.length());
}
}
}
@@ -245,8 +246,11 @@ public class SWTConsole extends Composite implements ConsoleManager {
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
@Override
- public String prompt() {
+ public String prompt() throws IOException {
synchronized (promptLock) {
+ if (isDisposed()) {
+ throw new IOException();
+ }
try {
Display.getDefault().syncExec(new Runnable() {
@SuppressWarnings("synthetic-access")
@@ -268,8 +272,11 @@ public class SWTConsole extends Composite implements ConsoleManager {
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
@Override
- public String prompt(final String message) {
+ public String prompt(final String message) throws IOException {
synchronized (promptLock) {
+ if (isDisposed()) {
+ throw new IOException();
+ }
try {
Display.getDefault().syncExec(new Runnable() {
@SuppressWarnings("synthetic-access")
@@ -284,6 +291,9 @@ public class SWTConsole extends Composite implements ConsoleManager {
});
prompting = true;
promptLock.wait();
+ if (isDisposed()) {
+ throw new IOException();
+ }
} catch (final InterruptedException e) {
command = null;
} finally {
@@ -292,7 +302,8 @@ public class SWTConsole extends Composite implements ConsoleManager {
@Override
public void run() {
lblPromptlabel.setText(prompt);
- lblPromptlabel.pack();
+ // relayout
+ SWTConsole.this.layout();
}
});
}
@@ -317,7 +328,8 @@ public class SWTConsole extends Composite implements ConsoleManager {
@Override
public void run() {
lblPromptlabel.setText(prompt);
- lblPromptlabel.pack();
+ // relayout
+ SWTConsole.this.layout();
}
});
}
@@ -325,9 +337,22 @@ public class SWTConsole extends Composite implements ConsoleManager {
/* (non-Javadoc)
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
@Override
- public void close() throws IOException {
+ public void close() {
+ synchronized (promptLock) {
+ promptLock.notify();
+ }
+ if (consoleInput.isDisposed()) {
+ return;
+ }
consoleInput.setEnabled(false);
consoleOutput.setEnabled(false);
}
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
+ @Override
+ public boolean isClosed() {
+ return isDisposed();
+ }
+
}
diff --git a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsoleShell.java b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsoleShell.java
index 91feb86..e4f0d6f 100644
--- a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsoleShell.java
+++ b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/SWTConsoleShell.java
@@ -79,4 +79,12 @@ public class SWTConsoleShell extends Shell {
public ConsoleManager getManager() {
return console;
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.widgets.Shell#dispose() */
+ @Override
+ public void dispose() {
+ super.dispose();
+ console.close();
+ }
}
diff --git a/gclc-swt/src/test/java/fr/bigeon/gclc/swt/AppTest.java b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/AppTest.java
deleted file mode 100644
index f706949..0000000
--- a/gclc-swt/src/test/java/fr/bigeon/gclc/swt/AppTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright E. Bigeon (2015)
- *
- * emmanuel@bigeon.fr
- *
- * This software is a computer program whose purpose is to
- * provide a swt window for console applications.
- *
- * This software is governed by the CeCILL 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
- * 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 license and that you accept its terms.
- */
-package fr.bigeon.gclc.swt;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-/** Unit test for simple App. */
-public class AppTest extends TestCase {
- protected static final long TWO_SECONDS = 2000;
-
- /** Create the test case
- *
- * @param testName name of the test case */
- public AppTest(String testName) {
- super(testName);
- }
-
- /** @return the suite of tests being tested */
- public static Test suite() {
- return new TestSuite(AppTest.class);
- }
-
- /** Rigourous Test :-) */
- @SuppressWarnings("static-method")
- public void testApp() {
-// Display display = new Display();
-// final Shell shell = new Shell(display);
-// shell.setLayout(new GridLayout(1, false));
-// SWTConsole swtConsole = new SWTConsole(shell, SWT.NONE);
-// swtConsole.setLayoutData(
-// new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
-// final ConsoleApplication appl = new ConsoleApplication(swtConsole,
-// "exit", "Hello", "See you");
-// try {
-// appl.add(new Command("long") {
-//
-// @Override
-// public String tip() {
-// return "a long running command";
-// }
-//
-// @Override
-// public void execute(String... args) {
-// try {
-// Thread.sleep(TWO_SECONDS);
-// } catch (InterruptedException e) {
-// // TODO Auto-generated catch block
-// e.printStackTrace();
-// }
-// }
-// });
-// } catch (InvalidCommandName e) {
-// // TODO Auto-generated catch block
-// e.printStackTrace();
-// }
-// shell.pack();
-// shell.open();
-// Thread applThread = new Thread(new Runnable() {
-//
-// @Override
-// public void run() {
-// appl.start();
-// Display.getDefault().syncExec(new Runnable() {
-// @Override
-// public void run() {
-// shell.dispose();
-// }
-// });
-// }
-// });
-// applThread.start();
-// while (!shell.isDisposed()) {
-// if (!display.readAndDispatch()) {
-// display.sleep();
-// }
-// }
-// display.dispose();
- assertTrue(true);
- }
-}
diff --git a/gclc-swt/src/test/java/fr/bigeon/gclc/swt/SWTConsoleShellTest.java b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/SWTConsoleShellTest.java
new file mode 100644
index 0000000..f057ce1
--- /dev/null
+++ b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/SWTConsoleShellTest.java
@@ -0,0 +1,100 @@
+/**
+ * gclc-swt:fr.bigeon.gclc.swt.SWTConsoleShellTest.java
+ * Created on: Jun 8, 2016
+ */
+package fr.bigeon.gclc.swt;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.swt.widgets.Display;
+import org.junit.Test;
+
+import fr.bigeon.gclc.ConsoleApplication;
+import fr.bigeon.gclc.command.Command;
+import fr.bigeon.gclc.exception.InvalidCommandName;
+import fr.bigeon.gclc.manager.ConsoleManager;
+
+/**
+ *
+ * TODO
+ *
+ * @author Emmanuel Bigeon
+ *
+ */
+public class SWTConsoleShellTest {
+
+ protected static final long TWO_SECONDS = 2000;
+
+ @Test
+ public void test() {
+ Display display = new Display();
+ final SWTConsoleShell shell = new SWTConsoleShell(display);
+ ConsoleManager swtConsole = shell.getManager();
+ try {
+ final ConsoleApplication appl = new ConsoleApplication(swtConsole,
+ "exit", "Hello", "See you");
+ appl.add(new Command("long") {
+
+ @Override
+ public String tip() {
+ return "a long running command";
+ }
+
+ @Override
+ public void execute(String... args) {
+ try {
+ Thread.sleep(TWO_SECONDS);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ });
+// shell.pack();
+ shell.open();
+ Thread applThread = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ appl.start();
+ }
+ });
+ Thread testThread = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(TWO_SECONDS);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ shell.dispose();
+ }
+ });
+ }
+ });
+ applThread.start();
+ testThread.start();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+// display.dispose();
+ assertTrue(appl.getManager().isClosed());
+ Thread.sleep(TWO_SECONDS);
+ assertFalse(appl.isRunning());
+ } catch (InvalidCommandName e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/gclc/pom.xml b/gclc/pom.xml
index fd343ae..30f1cf1 100644
--- a/gclc/pom.xml
+++ b/gclc/pom.xml
@@ -36,7 +36,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
gclc
- 1.1.3-SNAPSHOT
+ 1.2.0-SNAPSHOT
jar
http://www.bigeon.fr/emmanuel
diff --git a/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java b/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java
index 49c171b..69a8fa4 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java
@@ -36,12 +36,14 @@
* Created on: Sep 6, 2014 */
package fr.bigeon.gclc;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
+import fr.bigeon.gclc.command.ExitCommand;
import fr.bigeon.gclc.command.HelpExecutor;
import fr.bigeon.gclc.command.ICommand;
import fr.bigeon.gclc.command.ICommandProvider;
@@ -53,7 +55,6 @@ import fr.bigeon.gclc.exception.InvalidCommandName;
import fr.bigeon.gclc.i18n.Messages;
import fr.bigeon.gclc.manager.ConsoleManager;
import fr.bigeon.gclc.manager.SystemConsoleManager;
-import fr.bigeon.gclc.prompt.CLIPrompterMessages;
/**
* A {@link ConsoleApplication} is an application that require the user to input
@@ -64,7 +65,7 @@ import fr.bigeon.gclc.prompt.CLIPrompterMessages;
*
* {@link ConsoleApplication} app = new {@link ConsoleApplication#ConsoleApplication(String, String, String) ConsoleApplication("exit", "welcome", "see you latter")};
* app.{@link ConsoleApplication#add(ICommand) add}("my_command", new {@link ICommand MyCommand()});
- * app.start();
+ * app.{@link ConsoleApplication#start start}();
*
*
* That will launch in the console application that will display "welcome",
@@ -107,7 +108,10 @@ public class ConsoleApplication implements ICommandProvider {
* @param welcome the header message to display on launch of this
* application
* @param goodbye the message to display on exit
- * @throws InvalidCommandName if the exit command name is invalid */
+ * @throws InvalidCommandName if the exit command name is invalid
+ * @deprecated since 1.2.0, use the {@link #add(ICommand)} method to add the
+ * exit command */
+ @Deprecated
public ConsoleApplication(ConsoleManager manager, String exit,
String welcome, String goodbye) throws InvalidCommandName {
this(manager, welcome, goodbye);
@@ -118,7 +122,12 @@ public class ConsoleApplication implements ICommandProvider {
* @param welcome the header message to display on launch of this
* application
* @param goodbye the message to display on exit
- * @throws InvalidCommandName if the exit command name is invalid */
+ * @throws InvalidCommandName if the exit command name is invalid
+ * @deprecated since 1.2.0, use the {@link #add(ICommand)} method to add the
+ * command and create this console using the
+ * {@link #ConsoleApplication(ConsoleManager, String, String)}
+ * method with a {@link SystemConsoleManager} as argument */
+ @Deprecated
public ConsoleApplication(String exit, String welcome,
String goodbye) throws InvalidCommandName {
this(new SystemConsoleManager(), welcome, goodbye);
@@ -134,12 +143,19 @@ public class ConsoleApplication implements ICommandProvider {
*
* @param cmd the handle for help
* @return if the help command was added
- * @throws InvalidCommandName if the help command was not valid */
+ * @throws InvalidCommandName if the help command was not valid
+ * @deprecated since 1.2.0 use the {@link #add(ICommand)} with a
+ * {@link HelpExecutor} instead */
+ @Deprecated
public final boolean addHelpCommand(String cmd) throws InvalidCommandName {
return root.add(new HelpExecutor(cmd, manager, root));
}
- /** @param listener the listener to remove. */
+ /** Add a command request listener.
+ *
+ * A listener can listen several times to the same application.
+ *
+ * @param listener the listener to add. */
public final void addListener(CommandRequestListener listener) {
listeners.add(listener);
}
@@ -149,12 +165,14 @@ public class ConsoleApplication implements ICommandProvider {
* fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
* java.lang.String[]) */
@Override
- public final void executeSub(String command, String... args) {
+ public final void executeSub(String command,
+ String... args) throws CommandRunException {
root.executeSub(command, args);
}
/** Exit this running application before next command prompt */
public final void exit() {
+ LOGGER.fine("Request exiting application..."); //$NON-NLS-1$
running = false;
}
@@ -170,11 +188,12 @@ public class ConsoleApplication implements ICommandProvider {
return manager;
}
- /** @param cmd the command to interpret */
- public final void interpretCommand(String cmd) {
+ /** @param cmd the command to interpret
+ * @throws IOException if the manager was closed */
+ public final void interpretCommand(String cmd) throws IOException {
List args;
try {
- args = splitCommand(cmd);
+ args = GCLCConstants.splitCommand(cmd);
} catch (CommandParsingException e1) {
manager.println("Command line cannot be parsed"); //$NON-NLS-1$
LOGGER.log(Level.INFO, "Invalid user command " + cmd, e1); //$NON-NLS-1$
@@ -193,63 +212,7 @@ public class ConsoleApplication implements ICommandProvider {
}
}
- /** Splits a command in the diferrent arguments
- *
- * @param cmd the command to split in its parts
- * @return the list of argument preceded by the command name
- * @throws CommandParsingException if the parsing of the command failed */
- private static List splitCommand(String cmd) throws CommandParsingException {
- final List args = new ArrayList<>();
- // parse the string to separate arguments
- int index = 0;
- int startIndex = 0;
- boolean escaped = false;
- boolean inString = false;
- while (index < cmd.length()) {
- char c = cmd.charAt(index);
- index++;
- if (escaped || c == '\\') {
- escaped = !escaped;
- continue;
- }
- if (c == ' ' && !inString) {
- final String arg = cmd.substring(startIndex, index - 1);
- if (!arg.isEmpty()) {
- args.add(arg);
- }
- startIndex = index;
- } else if (c == '"') {
- if (inString) {
- inString = false;
- args.add(endOfString(cmd, startIndex, index));
- index++;
- startIndex = index;
- }
- inString = startIndex == index - 1;
- }
- }
- final String arg = cmd.substring(startIndex, cmd.length());
- if (!arg.isEmpty()) {
- args.add(arg);
- }
- return args;
- }
-
- /** @param cmd the command to parse
- * @param startIndex the starting point of the parsing
- * @param index the index of the current position
- * @return the argument
- * @throws CommandParsingException if the end of string does not mark end of
- * command and is not followed by a space */
- private static String endOfString(String cmd, int startIndex,
- int index) throws CommandParsingException {
- if (index + 1 < cmd.length() && cmd.charAt(index + 1) != ' ') {
- throw new CommandParsingException("Misplaced quote"); //$NON-NLS-1$
- }
- return cmd.substring(startIndex + 1, index - 1);
- }
-
- /** @param listener the listener to remove */
+ /** @param listener the listener to remove (once) */
public final void removeListener(CommandRequestListener listener) {
for (int i = 0; i < listeners.size(); i++) {
if (listeners.get(i) == listener) {
@@ -261,73 +224,41 @@ public class ConsoleApplication implements ICommandProvider {
/** Launches the prompting application */
public final void start() {
- if (header != null) {
- manager.println(header);
- }
- running = true;
- do {
- final String cmd = manager.prompt();
- if (cmd.isEmpty()) {
- continue;
+ try {
+ running = true;
+ if (header != null) {
+ manager.println(header);
}
- for (final CommandRequestListener listener : listeners) {
- listener.commandRequest(cmd);
+ do {
+ final String cmd = manager.prompt();
+ if (cmd == null || cmd.isEmpty()) {
+ continue;
+ }
+ for (final CommandRequestListener listener : listeners) {
+ listener.commandRequest(cmd);
+ }
+ interpretCommand(cmd);
+ } while (running);
+ if (footer != null) {
+ manager.println(footer);
}
- interpretCommand(cmd);
- } while (running);
- if (footer != null) {
- manager.println(footer);
+ LOGGER.fine("Exiting application."); //$NON-NLS-1$
+ } catch (IOException e) {
+ // The manager was closed
+ running = false;
+ LOGGER.log(Level.WARNING,
+ "The console manager was closed. Closing the application as no one can reach it.", //$NON-NLS-1$
+ e);
}
}
-}
-/**
- * A command to exit a {@link ConsoleApplication}.
- *
- * @author Emmanuel BIGEON */
-class ExitCommand implements ICommand {
- /** The exit command manual message key */
- private static final String EXIT_MAN = "exit.man"; //$NON-NLS-1$
- /** The tip of the exit command */
- private static final String EXIT = "exit.tip"; //$NON-NLS-1$
- /** The application that will be exited when this command runs */
- private final ConsoleApplication app;
- /** The exit command name */
- private final String name;
-
- /** @param name the name of the command
- * @param app the application to exit */
- public ExitCommand(String name, ConsoleApplication app) {
- this.name = name;
- this.app = app;
+ /** @return if the application is running */
+ public boolean isRunning() {
+ return running;
}
- /** The actions to take before exiting */
- public void beforeExit() {
- // Do nothing by default
- }
-
- @Override
- public final void execute(String... args) {
- beforeExit();
- app.exit();
- }
-
- /* (non-Javadoc)
- * @see fr.bigeon.gclc.command.ICommand#getCommandName() */
- @Override
- public String getCommandName() {
- return name;
- }
-
- @Override
- public void help(ConsoleManager manager, String... args) {
- manager.println(
- CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
- }
-
- @Override
- public String tip() {
- return CLIPrompterMessages.getString(EXIT);
+ /** @return the root */
+ public SubedCommand getRoot() {
+ return root;
}
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/GCLCConstants.java b/gclc/src/main/java/fr/bigeon/gclc/GCLCConstants.java
new file mode 100644
index 0000000..e16977a
--- /dev/null
+++ b/gclc/src/main/java/fr/bigeon/gclc/GCLCConstants.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright Bigeon Emmanuel (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * provide a generic framework for console applications.
+ *
+ * This software is governed by the CeCILL 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
+ * 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 license and that you accept its terms.
+ */
+/**
+ * gclc:fr.bigeon.gclc.GCLCConstants.java
+ * Created on: Jun 8, 2016
+ */
+package fr.bigeon.gclc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import fr.bigeon.gclc.exception.CommandParsingException;
+
+/** A Utility class for GCLC
+ *
+ * This class offers a method to split a line or arguments into the list of
+ * arguments.
+ *
+ * @author Emmanuel Bigeon */
+public class GCLCConstants {
+
+ /** Hide utility class constructor */
+ private GCLCConstants() {
+ // utility class
+ }
+
+ /** Splits a command in the diferrent arguments
+ *
+ * @param cmd the command to split in its parts
+ * @return the list of argument preceded by the command name
+ * @throws CommandParsingException if the parsing of the command failed */
+ public static List splitCommand(String cmd) throws CommandParsingException {
+ final List args = new ArrayList<>();
+ // parse the string to separate arguments
+ int index = 0;
+ int startIndex = 0;
+ boolean escaped = false;
+ boolean inString = false;
+ while (index < cmd.length()) {
+ char c = cmd.charAt(index);
+ index++;
+ if (escaped || c == '\\') {
+ escaped = !escaped;
+ continue;
+ }
+ if (c == ' ' && !inString) {
+ final String arg = cmd.substring(startIndex, index - 1);
+ if (!arg.isEmpty()) {
+ args.add(removeEscaped(arg));
+ }
+ startIndex = index;
+ } else if (c == '"') {
+ if (inString) {
+ args.add(endOfString(cmd, startIndex, index));
+ index++;
+ startIndex = index;
+ }
+ inString = startIndex == index - 1;
+ }
+ }
+ final String arg = cmd.substring(startIndex, cmd.length());
+ if (!arg.isEmpty()) {
+ args.add(arg);
+ }
+ return args;
+ }
+
+ /** @param arg the string to remove excaping character from
+ * @return the string without escape character */
+ private static String removeEscaped(String arg) {
+ StringBuilder builder = new StringBuilder();
+ int index = 0;
+ int endIndex = arg.indexOf('\\');
+ while (endIndex != -1) {
+ builder.append(arg.subSequence(index, endIndex));
+ index = endIndex + 1;
+ endIndex = arg.indexOf('\\', index + 1);
+ }
+ builder.append(arg.substring(index));
+ return builder.toString();
+ }
+
+ /** @param cmd the command to parse
+ * @param startIndex the starting point of the parsing
+ * @param index the index of the current position
+ * @return the argument
+ * @throws CommandParsingException if the end of string does not mark end of
+ * command and is not followed by a space */
+ private static String endOfString(String cmd, int startIndex,
+ int index) throws CommandParsingException {
+ if (index < cmd.length() && cmd.charAt(index) != ' ') {
+ throw new CommandParsingException("Misplaced quote"); //$NON-NLS-1$
+ }
+ return cmd.substring(startIndex + 1, index - 1);
+ }
+
+}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/Command.java b/gclc/src/main/java/fr/bigeon/gclc/command/Command.java
index 2fba973..e22433f 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/Command.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/Command.java
@@ -38,23 +38,25 @@
*/
package fr.bigeon.gclc.command;
+import java.io.IOException;
+
import fr.bigeon.gclc.manager.ConsoleManager;
/**
* A command to execute. It is mandatory that it has a name and that name cannot
- * start with minus character or contain space.
+ * start with minus character or contain spaces.
*
* A command can be executed, with parameters that will be provided as an array
* of strings.
*
- * The help mechanism can be overwritten, but is by default doing the following:
+ * The help mechanism is doing the following:
*
* - Print the command name
*
- Print the {@link #brief()} message
*
- Print a blank line
*
- Print "Usage:"
- *
- Print the usage pattern
- *
- Print the usage details
+ *
- Print the {@link #usagePattern() usage pattern}
+ *
- Print the {@link #usageDetail() usage details}
*
*
* The default behavior for the brief message is to print the tip preceeded by a
@@ -92,7 +94,8 @@ public abstract class Command implements ICommand {
* @see fr.bigeon.gclc.command.ICommand#help(fr.bigeon.gclc.ConsoleManager,
* java.lang.String) */
@Override
- public final void help(ConsoleManager manager, String... args) {
+ public final void help(ConsoleManager manager,
+ String... args) throws IOException {
manager.println(getCommandName());
manager.println(brief());
manager.println();
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/CommandProvider.java b/gclc/src/main/java/fr/bigeon/gclc/command/CommandProvider.java
index e9152a7..2f97d17 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/CommandProvider.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/CommandProvider.java
@@ -39,7 +39,9 @@ package fr.bigeon.gclc.command;
import java.util.HashSet;
import java.util.Set;
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.exception.InvalidCommandName;
+import fr.bigeon.gclc.i18n.Messages;
/**
* A command provider is a map of key word to command to execute
@@ -52,14 +54,11 @@ public class CommandProvider implements ICommandProvider {
private static final String SPACE = " "; //$NON-NLS-1$
/** The commands map */
protected final Set commands;
- /** The error command to be executed when the command isn't recognized */
- protected final ICommand error;
- /** @param error the error command */
- public CommandProvider(ICommand error) {
+ /** Create a command provider */
+ public CommandProvider() {
super();
commands = new HashSet<>();
- this.error = error;
}
/* (non-Javadoc)
@@ -75,14 +74,16 @@ public class CommandProvider implements ICommandProvider {
}
@Override
- public void executeSub(String cmd, String... args) {
+ public void executeSub(String cmd,
+ String... args) throws CommandRunException {
for (final ICommand command : commands) {
if (command.getCommandName().equals(cmd)) {
command.execute(args);
return;
}
}
- error.execute(cmd);
+ throw new CommandRunException(
+ Messages.getString("CommandProvider.unrecognized0", cmd)); //$NON-NLS-1$
}
/* (non-Javadoc)
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java
new file mode 100644
index 0000000..7a54eb6
--- /dev/null
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/ExitCommand.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright Bigeon Emmanuel (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * provide a generic framework for console applications.
+ *
+ * This software is governed by the CeCILL 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
+ * 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 license and that you accept its terms.
+ */
+/**
+ * gclc:fr.bigeon.gclc.ExitCommand.java
+ * Created on: Jun 8, 2016
+ */
+package fr.bigeon.gclc.command;
+
+import java.io.IOException;
+
+import fr.bigeon.gclc.ConsoleApplication;
+import fr.bigeon.gclc.manager.ConsoleManager;
+import fr.bigeon.gclc.prompt.CLIPrompterMessages;
+
+/**
+ * A command to exit a {@link ConsoleApplication}.
+ *
+ * @author Emmanuel BIGEON */
+public class ExitCommand implements ICommand {
+ /** The exit command manual message key */
+ private static final String EXIT_MAN = "exit.man"; //$NON-NLS-1$
+ /** The tip of the exit command */
+ private static final String EXIT = "exit.tip"; //$NON-NLS-1$
+ /** The application that will be exited when this command runs */
+ private final ConsoleApplication app;
+ /** The exit command name */
+ private final String name;
+
+ /** @param name the name of the command
+ * @param app the application to exit */
+ public ExitCommand(String name, ConsoleApplication app) {
+ this.name = name;
+ this.app = app;
+ }
+
+ /** The actions to take before exiting */
+ public void beforeExit() {
+ // Do nothing by default
+ }
+
+ @Override
+ public final void execute(String... args) {
+ beforeExit();
+ app.exit();
+ }
+
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.command.ICommand#getCommandName() */
+ @Override
+ public final String getCommandName() {
+ return name;
+ }
+
+ @Override
+ public void help(ConsoleManager manager,
+ String... args) throws IOException {
+ manager.println(
+ CLIPrompterMessages.getString(EXIT_MAN, (Object[]) args));
+ }
+
+ @Override
+ public String tip() {
+ return CLIPrompterMessages.getString(EXIT);
+ }
+}
\ No newline at end of file
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/HelpExecutor.java b/gclc/src/main/java/fr/bigeon/gclc/command/HelpExecutor.java
index ccaa55f..6eee60b 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/HelpExecutor.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/HelpExecutor.java
@@ -38,6 +38,9 @@
*/
package fr.bigeon.gclc.command;
+import java.io.IOException;
+
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.manager.ConsoleManager;
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
@@ -70,8 +73,12 @@ public class HelpExecutor extends Command {
/* (non-Javadoc)
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
@Override
- public void execute(String... args) {
- cmd.help(consoleManager, args);
+ public void execute(String... args) throws CommandRunException {
+ try {
+ cmd.help(consoleManager, args);
+ } catch (IOException e) {
+ throw new CommandRunException("Console manager closed", e); //$NON-NLS-1$
+ }
}
/* (non-Javadoc)
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java
index 263eb84..c1ac9ae 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/ICommand.java
@@ -38,6 +38,9 @@
*/
package fr.bigeon.gclc.command;
+import java.io.IOException;
+
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.manager.ConsoleManager;
/** The contract of commands
@@ -47,8 +50,10 @@ import fr.bigeon.gclc.manager.ConsoleManager;
* @author Emmanuel Bigeon */
public interface ICommand {
- /** @param args the arguments of the command (some expect an empty array) */
- void execute(String... args);
+ /** @param args the arguments of the command (some expect an empty array)
+ * @throws CommandRunException if the execution of the command failed for
+ * any reason */
+ void execute(String... args) throws CommandRunException;
/** @return the command's name */
String getCommandName();
@@ -68,8 +73,9 @@ public interface ICommand {
*
*
* @param manager the manager to print the data
- * @param args the arguments called with the help */
- void help(ConsoleManager manager, String... args);
+ * @param args the arguments called with the help
+ * @throws IOException if the manager was closed */
+ void help(ConsoleManager manager, String... args) throws IOException;
/** @return a tip on the command */
String tip();
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/ICommandProvider.java b/gclc/src/main/java/fr/bigeon/gclc/command/ICommandProvider.java
index f217aa9..294a419 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/ICommandProvider.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/ICommandProvider.java
@@ -36,6 +36,7 @@
* Created on: Sep 6, 2014 */
package fr.bigeon.gclc.command;
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.exception.InvalidCommandName;
/**
@@ -62,8 +63,10 @@ public interface ICommandProvider {
* the user for a choice.
*
* @param command the name of the command the user wishes to execute
- * @param args the arguments for the command */
- public void executeSub(String command, String... args);
+ * @param args the arguments for the command
+ * @throws CommandRunException if the command failed to run */
+ public void executeSub(String command,
+ String... args) throws CommandRunException;
/**
* This method provide the command with the given name found. If no command
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/ParametrizedCommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/ParametrizedCommand.java
index 141f7fa..aad57a7 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/ParametrizedCommand.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/ParametrizedCommand.java
@@ -38,11 +38,13 @@
*/
package fr.bigeon.gclc.command;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.manager.ConsoleManager;
/**
@@ -115,13 +117,12 @@ public abstract class ParametrizedCommand extends Command {
* @see fr.bigeon.gclc.command.Command#execute(java.lang.String[]) */
@SuppressWarnings("boxing")
@Override
- public final void execute(String... args) {
+ public final void execute(String... args) throws CommandRunException {
final CommandParameters parameters = new CommandParameters(
boolParams.keySet(), stringParams.keySet(), strict);
if (!parameters.parseArgs(args)) {
// ERROR the parameters could not be correctly parsed
- manager.println("Unable to read arguments"); //$NON-NLS-1$
- return;
+ throw new CommandRunException("Unable to read arguments"); //$NON-NLS-1$
}
final List toProvide = new ArrayList<>();
for (final String string : params.keySet()) {
@@ -133,13 +134,27 @@ public abstract class ParametrizedCommand extends Command {
}
}
// for each needed parameters that is missing, prompt the user.
+ fillParameters(toProvide, parameters);
+ doExecute(parameters);
+ }
+
+ /** @param parameters the parameter list to complete
+ * @param toProvide the parameters to ask for
+ * @throws CommandRunException if the manager was closed */
+ private void fillParameters(List toProvide,
+ CommandParameters parameters) throws CommandRunException {
for (final String string : toProvide) {
- String value = manager.prompt(string);
- while (value.isEmpty()) {
+ String value;
+ try {
value = manager.prompt(string);
+ while (value.isEmpty()) {
+ value = manager.prompt(string);
+ }
+ } catch (IOException e) {
+ throw new CommandRunException(
+ "Interactive command but manager closed...", e); //$NON-NLS-1$
}
parameters.set(string, value);
}
- doExecute(parameters);
}
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java
index 3709c5a..dc3e26b 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/SubedCommand.java
@@ -36,8 +36,10 @@
* Created on: Sep 6, 2014 */
package fr.bigeon.gclc.command;
+import java.io.IOException;
import java.util.Arrays;
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.exception.InvalidCommandName;
import fr.bigeon.gclc.manager.ConsoleManager;
@@ -61,44 +63,40 @@ public class SubedCommand implements ICommandProvider, ICommand {
/** The name of the command */
private final String name;
- /** @param name the name of the command
- * @param error the error to execute when called with wrong usage */
- public SubedCommand(String name, ICommand error) {
+ /** @param name the name of the command */
+ public SubedCommand(String name) {
this.name = name;
- provider = new CommandProvider(error);
+ provider = new CommandProvider();
noArgCommand = null;
tip = null;
}
/** @param name the name of the command
* @param noArgCommand the command to execute when no extra parameter are
- * provided
- * @param error the error to execute when called with wrong usage */
- public SubedCommand(String name, ICommand error, ICommand noArgCommand) {
+ * provided */
+ public SubedCommand(String name, ICommand noArgCommand) {
this.name = name;
- provider = new CommandProvider(error);
+ provider = new CommandProvider();
this.noArgCommand = noArgCommand;
tip = null;
}
/** @param name the name of the command
* @param noArgCommand the command to execute
- * @param error the error to execute when called with wrong usage
* @param tip the help tip associated */
- public SubedCommand(String name, ICommand error, ICommand noArgCommand,
+ public SubedCommand(String name, ICommand noArgCommand,
String tip) {
this.name = name;
- provider = new CommandProvider(error);
+ provider = new CommandProvider();
this.noArgCommand = noArgCommand;
this.tip = tip;
}
/** @param name the name of the command
- * @param error the error to execute when called with wrong usage
* @param tip the help tip associated */
- public SubedCommand(String name, ICommand error, String tip) {
+ public SubedCommand(String name, String tip) {
this.name = name;
- provider = new CommandProvider(error);
+ provider = new CommandProvider();
noArgCommand = null;
this.tip = tip;
}
@@ -111,12 +109,12 @@ public class SubedCommand implements ICommandProvider, ICommand {
/* (non-Javadoc)
* @see fr.bigeon.acide.Command#execute(java.lang.String[]) */
@Override
- public void execute(String... args) {
+ public void execute(String... args) throws CommandRunException {
if (args.length == 0 || args[0].startsWith("-")) { //$NON-NLS-1$
if (noArgCommand != null) {
noArgCommand.execute(args);
} else {
- provider.error.execute(args);
+ throw new CommandRunException("Unrecognized command"); //$NON-NLS-1$
}
} else {
executeSub(args[0], Arrays.copyOfRange(args, 1, args.length));
@@ -128,7 +126,8 @@ public class SubedCommand implements ICommandProvider, ICommand {
* fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
* java.lang.String[]) */
@Override
- public void executeSub(String command, String... args) {
+ public void executeSub(String command,
+ String... args) throws CommandRunException {
provider.executeSub(command, args);
}
@@ -147,28 +146,27 @@ public class SubedCommand implements ICommandProvider, ICommand {
/* (non-Javadoc)
* @see fr.bigeon.gclc.command.Command#help() */
@Override
- public void help(ConsoleManager manager, String... args) {
+ public void help(ConsoleManager manager,
+ String... args) throws IOException {
if (args.length != 0 && !args[0].startsWith("-")) { //$NON-NLS-1$
// Specific
final ICommand c = get(args[0]);
if (c != null) {
c.help(manager, Arrays.copyOfRange(args, 1, args.length));
- } else {
- provider.error.execute(args);
}
} else {
// Generic
- if (noArgCommand != null && noArgCommand.tip() != null) {
- manager.println(TAB + noArgCommand.tip());
- }
- for (final ICommand cmd : provider.commands) {
- if (cmd.tip() == null) {
- manager.println(TAB + cmd.getCommandName());
- } else {
- manager.println(TAB + cmd.getCommandName() + ": " + //$NON-NLS-1$
- cmd.tip());
+ if (noArgCommand != null && noArgCommand.tip() != null) {
+ manager.println(TAB + noArgCommand.tip());
+ }
+ for (final ICommand cmd : provider.commands) {
+ if (cmd.tip() == null) {
+ manager.println(TAB + cmd.getCommandName());
+ } else {
+ manager.println(TAB + cmd.getCommandName() + ": " + //$NON-NLS-1$
+ cmd.tip());
+ }
}
- }
}
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/command/UnrecognizedCommand.java b/gclc/src/main/java/fr/bigeon/gclc/command/UnrecognizedCommand.java
index fc82832..777f7b4 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/UnrecognizedCommand.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/UnrecognizedCommand.java
@@ -38,6 +38,9 @@
*/
package fr.bigeon.gclc.command;
+import java.io.IOException;
+
+import fr.bigeon.gclc.exception.CommandRunException;
import fr.bigeon.gclc.manager.ConsoleManager;
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
@@ -62,12 +65,17 @@ public final class UnrecognizedCommand implements ICommand {
}
@Override
- public void execute(String... args) {
- if (args.length > 0) {
- manager.println(CLIPrompterMessages.getString(UNRECOGNIZED_CMD,
- (Object[]) args));
- } else {
- manager.println(CLIPrompterMessages.getString(EXPECTED_CMD));
+ public void execute(String... args) throws CommandRunException {
+
+ try {
+ if (args.length > 0) {
+ manager.println(CLIPrompterMessages.getString(UNRECOGNIZED_CMD,
+ (Object[]) args));
+ } else {
+ manager.println(CLIPrompterMessages.getString(EXPECTED_CMD));
+ }
+ } catch (IOException e) {
+ throw new CommandRunException("Manager closed", e); //$NON-NLS-1$
}
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java b/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java
index 35a14a5..d4713ee 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/exception/CommandRunException.java
@@ -42,7 +42,7 @@ package fr.bigeon.gclc.exception;
* An exception thrown when a command failed to run correctly.
*
* @author Emmanuel BIGEON */
-public class CommandRunException extends RuntimeException {
+public class CommandRunException extends Exception {
/**
*
diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleManager.java b/gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleManager.java
index 37cc72e..b3d9c14 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleManager.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/manager/ConsoleManager.java
@@ -52,21 +52,32 @@ public interface ConsoleManager {
/** @return the prompt prefix */
String getPrompt();
- /** @param text the message to print (without line break at the end). */
- void print(String text);
+ /** @param text the message to print (without line break at the end).
+ * @throws IOException if the manager is closed or could not read the
+ * prompt */
+ void print(String text) throws IOException;
- /** Prints an end of line */
- void println();
+ /** Prints an end of line
+ *
+ * @throws IOException if the manager is closed or could not read the
+ * prompt */
+ void println() throws IOException;
- /** @param message the message to print */
- void println(String message);
+ /** @param message the message to print
+ * @throws IOException if the manager is closed or could not read the
+ * prompt */
+ void println(String message) throws IOException;
- /** @return the user inputed string */
- String prompt();
+ /** @return the user inputed string
+ * @throws IOException if the manager is closed or could not read the
+ * prompt */
+ String prompt() throws IOException;
/** @param message the message to prompt the user
- * @return the user inputed string */
- String prompt(String message);
+ * @return the user inputed string
+ * @throws IOException if the manager is closed or could not read the
+ * prompt */
+ String prompt(String message) throws IOException;
/**
* Set a prompting prefix.
@@ -74,6 +85,11 @@ public interface ConsoleManager {
* @param prompt the prompt */
void setPrompt(String prompt);
- /** @throws IOException if the close raised an exception */
+ /** Closes the manager.
+ *
+ * @throws IOException if the close raised an exception */
void close() throws IOException;
+
+ /** @return if the manager is closed. */
+ boolean isClosed();
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/SystemConsoleManager.java b/gclc/src/main/java/fr/bigeon/gclc/manager/SystemConsoleManager.java
index 286edb6..e985b75 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/manager/SystemConsoleManager.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/manager/SystemConsoleManager.java
@@ -38,8 +38,10 @@
*/
package fr.bigeon.gclc.manager;
+import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -64,13 +66,15 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
/** The print stream */
private final PrintStream out;
/** The input stream */
- private final InputStream in;
+ private final BufferedReader in;
+
+ /** If the manager is closed */
+ private boolean closed = false;
/** This default constructor relies on the system defined standart output
* and input stream. */
public SystemConsoleManager() {
- out = System.out; // NOSONAR
- in = System.in;
+ this(System.out, System.in);
}
/** @param out the output stream
@@ -78,7 +82,7 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
public SystemConsoleManager(PrintStream out, InputStream in) {
super();
this.out = out;
- this.in = in;
+ this.in = new BufferedReader(new InputStreamReader(in));
}
/** @return the prompt */
@@ -90,47 +94,60 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#print(java.lang.Object) */
@Override
- public void print(String object) {
+ public void print(String object) throws IOException {
+ if (closed) {
+ throw new IOException();
+ }
out.print(object);
}
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#println() */
@Override
- public void println() {
+ public void println() throws IOException {
+ if (closed) {
+ throw new IOException();
+ }
out.println();
}
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#println(java.lang.Object) */
@Override
- public void println(String object) {
+ public void println(String object) throws IOException {
+ if (closed) {
+ throw new IOException();
+ }
out.println(object);
}
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#prompt() */
@Override
- public String prompt() {
+ public String prompt() throws IOException {
return prompt(new String() + prompt);
}
/* (non-Javadoc)
* @see fr.bigeon.gclc.ConsoleManager#prompt(java.lang.String) */
@Override
- public String prompt(String message) {
+ public String prompt(String message) throws IOException {
+ if (closed) {
+ throw new IOException();
+ }
String result = new String();
out.print(message + ' ');
char c;
try {
- c = (char) in.read();
- while (c != System.lineSeparator().charAt(0)) {
- result += c;
- c = (char) in.read();
- }
- while (in.available() != 0) {
- in.read();
- }
+ result = in.readLine();
+// c = (char) in.read();
+// while (c != System.lineSeparator().charAt(0)) {
+// result += c;
+// c = (char) in.read();
+// }
+// while (in.available() != 0) {
+// in.read();
+// }
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, "Unable to read prompt", e); //$NON-NLS-1$
}
@@ -147,7 +164,14 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
* @see fr.bigeon.gclc.manager.ConsoleManager#close() */
@Override
public void close() throws IOException {
- in.close();
+ closed = true;
+ }
+
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.manager.ConsoleManager#isClosed() */
+ @Override
+ public boolean isClosed() {
+ return closed;
}
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/prompt/CLIPrompter.java b/gclc/src/main/java/fr/bigeon/gclc/prompt/CLIPrompter.java
index adf5d43..efd9c39 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/prompt/CLIPrompter.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/prompt/CLIPrompter.java
@@ -36,6 +36,7 @@
* Created on: Jul 31, 2014 */
package fr.bigeon.gclc.prompt;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -80,9 +81,10 @@ public class CLIPrompter {
* @param choices the choices
* @param cancel the cancel option if it exists
* @return the number of choices plus one (or the number of choices if there
- * is a cancel) */
+ * is a cancel)
+ * @throws IOException if the manager was closed */
private static int listChoices(ConsoleManager manager, List choices,
- String cancel) {
+ String cancel) throws IOException {
int index = 0;
for (final U u : choices) {
manager.println(index++ + ") " + u); //$NON-NLS-1$
@@ -95,9 +97,10 @@ public class CLIPrompter {
/** @param manager the manager
* @param message the prompting message
- * @return the choice */
+ * @return the choice
+ * @throws IOException if the manager was closed */
public static boolean promptBoolean(ConsoleManager manager,
- String message) {
+ String message) throws IOException {
String result = manager
.prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES));
boolean first = true;
@@ -134,11 +137,12 @@ public class CLIPrompter {
* @param message the message
* @param cancel the cancel option, or null
* @param the type of elements
- * @return the choice */
+ * @return the choice
+ * @throws IOException if the manager was closed */
@SuppressWarnings("boxing")
public static U promptChoice(ConsoleManager manager, List keys,
List choices, String message,
- String cancel) {
+ String cancel) throws IOException {
final Integer index = promptChoice(manager, keys, message, cancel);
if (index == null) {
return null;
@@ -153,10 +157,11 @@ public class CLIPrompter {
* @param choicesMap the map of label to actual objects
* @param message the prompting message
* @param cancel the cancel option if it exists (null otherwise)
- * @return the chosen object */
+ * @return the chosen object
+ * @throws IOException if the manager was closed */
public static T promptChoice(ConsoleManager manager, List choices,
Map choicesMap, String message,
- String cancel) {
+ String cancel) throws IOException {
return choicesMap.get(choices.get(
promptChoice(manager, choices, message, cancel).intValue()));
}
@@ -166,11 +171,12 @@ public class CLIPrompter {
* @param choices the list of choices
* @param message the prompting message
* @param cancel the cancel option, or null
- * @return the index of the choice */
+ * @return the index of the choice
+ * @throws IOException if the manager was closed */
@SuppressWarnings("boxing")
public static Integer promptChoice(ConsoleManager manager,
List choices, String message,
- String cancel) {
+ String cancel) throws IOException {
manager.println(message);
final int index = listChoices(manager, choices, cancel);
String result = ""; //$NON-NLS-1$
@@ -207,18 +213,21 @@ public class CLIPrompter {
* @param choicesMap the map of label to actual objects
* @param message the prompting message
* @param cancel the cancel option (or null)
- * @return the chosen object */
+ * @return the chosen object
+ * @throws IOException if the manager was closed */
public static T promptChoice(ConsoleManager manager,
Map choicesMap, String message,
- String cancel) {
+ String cancel) throws IOException {
return promptChoice(manager, new ArrayList<>(choicesMap.keySet()),
choicesMap, message, cancel);
}
/** @param manager the manager
* @param message the prompt message
- * @return the integer */
- public static int promptInteger(ConsoleManager manager, String message) {
+ * @return the integer
+ * @throws IOException if the manager was closed */
+ public static int promptInteger(ConsoleManager manager,
+ String message) throws IOException {
boolean still = true;
int r = 0;
while (still) {
@@ -243,9 +252,10 @@ public class CLIPrompter {
*
* @param manager the manager
* @param message the message
- * @return the list of user inputs */
+ * @return the list of user inputs
+ * @throws IOException if the manager was closed */
public static List promptList(ConsoleManager manager,
- String message) {
+ String message) throws IOException {
return promptList(manager, message,
CLIPrompterMessages.getString("promptlist.exit.defaultkey")); //$NON-NLS-1$
}
@@ -255,9 +265,11 @@ public class CLIPrompter {
* @param manager the manager
* @param message the message
* @param ender the ending sequence for the list
- * @return the list of user inputs */
+ * @return the list of user inputs
+ * @throws IOException if the manager was closed */
public static List promptList(ConsoleManager manager,
- String message, String ender) {
+ String message,
+ String ender) throws IOException {
final List strings = new ArrayList<>();
manager.println(
message + CLIPrompterMessages.getString(LIST_DISP_KEY, ender));
@@ -275,9 +287,10 @@ public class CLIPrompter {
*
* @param manager the manager
* @param message the prompting message
- * @return the text */
+ * @return the text
+ * @throws IOException if the manager was closed */
public static String promptLongText(ConsoleManager manager,
- String message) {
+ String message) throws IOException {
return promptLongText(manager, message, CLIPrompterMessages
.getString("promptlongtext.exit.defaultkey")); //$NON-NLS-1$
}
@@ -287,9 +300,10 @@ public class CLIPrompter {
* @param manager the manager
* @param message the prompting message
* @param ender the ender character
- * @return the text */
+ * @return the text
+ * @throws IOException if the manager was closed */
public static String promptLongText(ConsoleManager manager, String message,
- String ender) {
+ String ender) throws IOException {
manager.println(message + CLIPrompterMessages
.getString("promptlongtext.exit.dispkey", ender)); //$NON-NLS-1$
String res = manager.prompt(PROMPT);
@@ -308,11 +322,12 @@ public class CLIPrompter {
* @param choices the real choices
* @param message the message
* @param the type of elements
- * @return the choice */
+ * @return the choice
+ * @throws IOException if the manager was closed */
public static List promptMultiChoice(ConsoleManager manager,
List keys,
List choices,
- String message) {
+ String message) throws IOException {
final List indices = promptMultiChoice(manager, keys, message);
final List userChoices = new ArrayList<>();
for (final Integer integer : indices) {
@@ -327,11 +342,12 @@ public class CLIPrompter {
* @param choices the list of labels (in order to be displayed)
* @param choicesMap the map of label to actual objects
* @param message the prompting message
- * @return the chosen objects (or an empty list) */
+ * @return the chosen objects (or an empty list)
+ * @throws IOException if the manager was closed */
public static List promptMultiChoice(ConsoleManager manager,
List choices,
Map choicesMap,
- String message) {
+ String message) throws IOException {
final List chs = promptMultiChoice(manager, choices, message);
final List userChoices = new ArrayList<>();
for (final Integer integer : chs) {
@@ -344,11 +360,12 @@ public class CLIPrompter {
* @param the type of choices
* @param choices the list of choices
* @param message the prompting message
- * @return the indices of the choices */
+ * @return the indices of the choices
+ * @throws IOException if the manager was closed */
@SuppressWarnings("boxing")
public static List promptMultiChoice(ConsoleManager manager,
List choices,
- String message) {
+ String message) throws IOException {
manager.println(message);
final int index = listChoices(manager, choices, null);
String result = ""; //$NON-NLS-1$
@@ -404,10 +421,11 @@ public class CLIPrompter {
* @param The real choices objects
* @param choicesMap the map of label to actual objects
* @param message the prompting message
- * @return the chosen objects */
+ * @return the chosen objects
+ * @throws IOException if the manager was closed */
public static List promptMultiChoice(ConsoleManager manager,
Map choicesMap,
- String message) {
+ String message) throws IOException {
return promptMultiChoice(manager, new ArrayList<>(choicesMap.keySet()),
choicesMap, message);
}
@@ -415,9 +433,10 @@ public class CLIPrompter {
/** @param manager the manager
* @param prompt the prompting message
* @param reprompt the prompting message after empty input
- * @return the non empty input */
+ * @return the non empty input
+ * @throws IOException if the manager was closed */
public static String promptNonEmpty(ConsoleManager manager, String prompt,
- String reprompt) {
+ String reprompt) throws IOException {
String res = manager.prompt(prompt);
while (res.isEmpty()) {
res = manager.prompt(reprompt);
diff --git a/gclc/src/main/resources/fr/bigeon/gclc/l10n/messages.properties b/gclc/src/main/resources/fr/bigeon/gclc/l10n/messages.properties
index 4b2f309..380b34f 100644
--- a/gclc/src/main/resources/fr/bigeon/gclc/l10n/messages.properties
+++ b/gclc/src/main/resources/fr/bigeon/gclc/l10n/messages.properties
@@ -1 +1,2 @@
+CommandProvider.unrecognized=Unrecognized command '{0}'
ConsoleApplication.cmd.failed=The command '{0}' failed due to :
diff --git a/gclc/src/test/java/fr/bigeon/gclc/ConsoleApplicationTest.java b/gclc/src/test/java/fr/bigeon/gclc/ConsoleApplicationTest.java
new file mode 100644
index 0000000..758cbdb
--- /dev/null
+++ b/gclc/src/test/java/fr/bigeon/gclc/ConsoleApplicationTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright Bigeon Emmanuel (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * provide a generic framework for console applications.
+ *
+ * This software is governed by the CeCILL 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
+ * 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 license and that you accept its terms.
+ */
+/**
+ * gclc:fr.bigeon.gclc.ConsoleApplicationTest.java
+ * Created on: Jun 9, 2016
+ */
+package fr.bigeon.gclc;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import org.junit.Test;
+
+import fr.bigeon.gclc.manager.SystemConsoleManager;
+
+/** Test class for ConsoleApplication
+ *
+ * @author Emmanuel Bigeon */
+@SuppressWarnings("static-method")
+public class ConsoleApplicationTest {
+
+ protected static final long THREE_SECONDS = 3000;
+
+ /** Test the base of a console application */
+ @Test
+ public void test() {
+ ConsoleTestApplication app = new ConsoleTestApplication(
+ new SystemConsoleManager());
+ app.exit();
+ }
+
+ @Test
+ public void executionTest() {
+ try {
+ final PipedOutputStream src = new PipedOutputStream();
+ InputStream in = new PipedInputStream(src);
+
+ final PipedInputStream snk = new PipedInputStream();
+ PrintStream out = new PrintStream(new PipedOutputStream(snk));
+ final ConsoleTestApplication app = new ConsoleTestApplication(
+ new SystemConsoleManager(out, in));
+ Thread th = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ app.start();
+ }
+ });
+
+ th.start();
+
+ Thread test = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ try (PrintWriter writer = new PrintWriter(src, true)) {
+ writer.println("test");
+ writer.println("long");
+ writer.println("exit");
+ }
+ }
+ });
+ test.start();
+ try {
+ th.join();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ try {
+ test.join();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ } catch (IOException e) {
+ fail("pipe creation"); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/gclc/src/test/java/fr/bigeon/gclc/ConsoleTestApplication.java b/gclc/src/test/java/fr/bigeon/gclc/ConsoleTestApplication.java
new file mode 100644
index 0000000..babe0ef
--- /dev/null
+++ b/gclc/src/test/java/fr/bigeon/gclc/ConsoleTestApplication.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright Bigeon Emmanuel (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * provide a generic framework for console applications.
+ *
+ * This software is governed by the CeCILL 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
+ * 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 license and that you accept its terms.
+ */
+package fr.bigeon.gclc;
+
+import java.io.IOException;
+
+import fr.bigeon.gclc.ConsoleApplication;
+import fr.bigeon.gclc.command.Command;
+import fr.bigeon.gclc.command.ExitCommand;
+import fr.bigeon.gclc.command.HelpExecutor;
+import fr.bigeon.gclc.exception.CommandRunException;
+import fr.bigeon.gclc.exception.InvalidCommandName;
+import fr.bigeon.gclc.manager.ConsoleManager;
+
+/** A test-purpose application
+ *
+ * @author Emmanuel Bigeon */
+public class ConsoleTestApplication extends ConsoleApplication {
+
+ /** Exit command */
+ public static final String EXIT = "exit"; //$NON-NLS-1$
+ /** Two seconds in milliseconds */
+ protected static final long TWO_SECONDS = 2000;
+
+ /** @param manager the manager */
+ @SuppressWarnings("nls")
+ public ConsoleTestApplication(final ConsoleManager manager) {
+ super(manager, "Welcome to the test application. Type help or test.",
+ "See you");
+ try {
+ add(new ExitCommand(EXIT, this));
+ add(new HelpExecutor("help", manager, this.getRoot()));
+ add(new Command("test") {
+
+ @Override
+ public String tip() {
+ return "A test command";
+ }
+
+ @Override
+ public void execute(String... args) throws CommandRunException {
+ try {
+ manager.println("Test command ran fine");
+ } catch (IOException e) {
+ throw new CommandRunException("manager closed", e);
+ }
+ }
+ });
+ add(new Command("long") {
+
+ @Override
+ public String tip() {
+ return "A long execution command";
+ }
+
+ @Override
+ public void execute(String... args) throws CommandRunException {
+ try {
+ manager.println("Waita minute");
+ Thread.sleep(TWO_SECONDS);
+ manager.println("done!");
+ } catch (IOException e) {
+ throw new CommandRunException("manager closed", e);
+ } catch (InterruptedException e) {
+ throw new CommandRunException("wait interrupted", e);
+ }
+ }
+ });
+ } catch (final InvalidCommandName e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/gclc/src/test/java/fr/bigeon/gclc/GCLCConstantsTest.java b/gclc/src/test/java/fr/bigeon/gclc/GCLCConstantsTest.java
new file mode 100644
index 0000000..9641011
--- /dev/null
+++ b/gclc/src/test/java/fr/bigeon/gclc/GCLCConstantsTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright Bigeon Emmanuel (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * provide a generic framework for console applications.
+ *
+ * This software is governed by the CeCILL 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
+ * 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 license and that you accept its terms.
+ */
+/**
+ * gclc:fr.bigeon.gclc.GCLCConstantsTest.java
+ * Created on: Jun 8, 2016
+ */
+package fr.bigeon.gclc;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import fr.bigeon.gclc.exception.CommandParsingException;
+
+/** Test class for {@link GCLCConstants}
+ *
+ * @author Emmanuel Bigeon */
+@SuppressWarnings({"nls", "static-method"})
+public class GCLCConstantsTest {
+
+ /**
+ * Test method for {@link fr.bigeon.gclc.GCLCConstants#splitCommand(java.lang.String)}.
+ */
+ @Test
+ public void testSplitCommand() {
+ List res;
+ try {
+ res = GCLCConstants.splitCommand("aCommand");
+ } catch (CommandParsingException e) {
+ fail("Unable to parse simple command"); //$NON-NLS-1$
+ return;
+ }
+ assertTrue(res.size() == 1);
+ assertTrue(res.get(0).equals("aCommand"));
+
+ try {
+ res = GCLCConstants.splitCommand("aCommand with some arguments");
+ } catch (CommandParsingException e) {
+ fail("Unable to parse command with arguments"); //$NON-NLS-1$
+ return;
+ }
+ assertTrue(res.size() == 4);
+ assertTrue(res.get(0).equals("aCommand"));
+ assertTrue(res.get(1).equals("with"));
+ assertTrue(res.get(2).equals("some"));
+ assertTrue(res.get(3).equals("arguments"));
+ try {
+ res = GCLCConstants.splitCommand("aCommand with some arguments");
+ } catch (CommandParsingException e) {
+ fail("Unable to parse command with arguments and double whitspaces"); //$NON-NLS-1$
+ return;
+ }
+ assertTrue(res.size() == 4);
+ assertTrue(res.get(0).equals("aCommand"));
+ assertTrue(res.get(1).equals("with"));
+ assertTrue(res.get(2).equals("some"));
+ assertTrue(res.get(3).equals("arguments"));
+ try {
+ res = GCLCConstants
+ .splitCommand("aCommand \"with some\" arguments");
+ } catch (CommandParsingException e) {
+ fail("Unable to parse command with string argument"); //$NON-NLS-1$
+ return;
+ }
+ assertTrue(res.size() == 3);
+ assertTrue(res.get(0).equals("aCommand"));
+ assertTrue(res.get(1).equals("with some"));
+ assertTrue(res.get(2).equals("arguments"));
+ try {
+ res = GCLCConstants.splitCommand("aCommand with\\ some arguments");
+ } catch (CommandParsingException e) {
+ fail("Unable to parse command with arguments with escaped whitspaces"); //$NON-NLS-1$
+ return;
+ }
+ assertTrue(res.size() == 3);
+ assertTrue(res.get(0).equals("aCommand"));
+ assertTrue(res.get(1).equals("with some"));
+ assertTrue(res.get(2).equals("arguments"));
+ try {
+ res = GCLCConstants
+ .splitCommand("aCommand wi\\\"th some arguments");
+ } catch (CommandParsingException e) {
+ fail("Unable to parse command with string argument"); //$NON-NLS-1$
+ return;
+ }
+ assertTrue(res.size() == 4);
+ assertTrue(res.get(0).equals("aCommand"));
+ assertTrue(res.get(1).equals("wi\"th"));
+ assertTrue(res.get(2).equals("some"));
+ assertTrue(res.get(3).equals("arguments"));
+
+ // Wrong lines?
+ try {
+ res = GCLCConstants
+ .splitCommand("aCommand with \"some ar\"guments");
+ fail("Parsing argument with string cut");
+ } catch (CommandParsingException e) {
+ // OK
+ }
+ }
+
+}