diff --git a/gclc-socket/.gitignore b/gclc-socket/.gitignore
new file mode 100644
index 0000000..8bd3a05
--- /dev/null
+++ b/gclc-socket/.gitignore
@@ -0,0 +1,4 @@
+/target/
+/.settings/
+/.classpath
+/.project
diff --git a/gclc-socket/pom.xml b/gclc-socket/pom.xml
new file mode 100644
index 0000000..23420ed
--- /dev/null
+++ b/gclc-socket/pom.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ * To use this application, the following flow should be used: + * + *
+ * SocketConsoleApplicationShell shell = new SocketConsoleApplicationShell(); + * ConsoleApplication myApplication = new MyConsoleApplication(shell.getConsoleManager(), ...); + * shell.setApplication(myApplication); + * Thread th = new Thread(shell); + * th.start(); + *+ *
+ * This will start the application in a separate thread. The application will be
+ * listening on the given socket and writing back on it. If this is all your
+ * application, you should then {@link Thread#join()} the thread to wait for the
+ * end of the execution.
+ *
+ * @author Emmanuel Bigeon */
+public class SocketConsoleApplicationShell implements Runnable {
+
+ /** The end of line character */
+ protected static final String EOL = "\n"; //$NON-NLS-1$
+ /** The encoder */
+ private static final StringEncoder ENCODER = new StringEncoder("%", Arrays.asList(EOL)); //$NON-NLS-1$
+ /** The listening port */
+ private final int port;
+ /** The output */
+ private PrintWriter output;
+ /** The input reader */
+ private BufferedReader input;
+ /** The input */
+ private final PipedInputStream consoleInput = new PipedInputStream();
+ /** The application */
+ private ConsoleApplication app;
+ /** The session closing command */
+ private final String close;
+ /** The running status */
+ private boolean running;
+ /** If the prompt should be next activity */
+ private boolean doPrompt = false;
+ /** An object to lock on for prompt */
+ private final Object promptingLock = new Object();
+
+ /** The console manager implementation */
+ private final ConsoleManager consoleManager = new ConsoleManager() {
+
+ private String prompt = new String();
+ private StringBuffer buffer = new StringBuffer();
+
+ @Override
+ public void setPrompt(String prompt) {
+ this.prompt = prompt;
+ }
+
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public String prompt(String message) {
+ buffer.append(message);
+ String userInput = new String();
+ boolean prompting = true;
+ while (prompting) {
+ output.println(ENCODER.encode(buffer.toString()));
+ try {
+ synchronized (promptingLock) {
+ doPrompt = true;
+ promptingLock.notify();
+ }
+ userInput = input.readLine();
+ doPrompt = false;
+ prompting = false;
+ } catch (final IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ buffer = new StringBuffer();
+ return userInput;
+ }
+
+ @Override
+ public String prompt() {
+ return prompt(prompt);
+ }
+
+ @Override
+ public void println(String message) {
+ buffer.append(message + EOL);
+
+ }
+
+ @Override
+ public void println() {
+ buffer.append(EOL);
+ }
+
+ @Override
+ public void print(String text) {
+ buffer.append(text);
+ }
+
+ @Override
+ public String getPrompt() {
+ return prompt;
+ }
+ };
+ /** The auto close flag. if this is true, every request closes the session
+ * after its call */
+ private final boolean autoClose;
+
+ /** The runnable class that will actually have the application running.
+ *
+ * @author Emmanuel Bigeon */
+ private class ConsoleRunnable implements Runnable {
+
+ /**
+ *
+ */
+ public ConsoleRunnable() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run() */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run() {
+ running = true;
+ app.start();
+ running = false;
+ synchronized (promptingLock) {
+ promptingLock.notifyAll();
+ }
+ }
+
+ }
+
+ /** TODO Describe SocketConsoleApplicationShell.java Constructor
+ *
+ * @param port the port to listen to
+ * @param close the session closing command */
+ public SocketConsoleApplicationShell(int port, String close) {
+ this.port = port;
+ this.close = close;
+ this.autoClose = false;
+ }
+
+ /** TODO Describe SocketConsoleApplicationShell.java Constructor
+ *
+ * @param port the port to listen to
+ * @param autoClose if the session must be closed once the request has been
+ * sent */
+ public SocketConsoleApplicationShell(int port, boolean autoClose) {
+ this.port = port;
+ this.close = null;
+ this.autoClose = autoClose;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run() */
+ @Override
+ public void run() {
+ try (ServerSocket serverSocket = new ServerSocket(port)) {
+ final ConsoleRunnable runnable = new ConsoleRunnable();
+ final Thread appTh = new Thread(runnable);
+ running = true;
+ try (PipedOutputStream outStream = new PipedOutputStream();
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outStream))) {
+ consoleInput.connect(outStream);
+ try (BufferedReader inBuf = new BufferedReader(new InputStreamReader(consoleInput))) {
+ input = inBuf;
+ while (running) {
+ try (Socket clientSocket = serverSocket.accept();
+ PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(clientSocket.getInputStream()));) {
+ output = out;
+ // Initiate application
+ if (!appTh.isAlive()) {
+ appTh.start();
+ } else {
+ output.println("Reconnected"); //$NON-NLS-1$
+ }
+ synchronized (promptingLock) {
+ String ln;
+ if (!doPrompt) try {
+ promptingLock.wait();
+ } catch (final InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ while (running && (ln = in.readLine()) != null) {
+ if (ln.equals(close)) {
+ break;
+ }
+ writer.write(ln + EOL);
+ writer.flush();
+ try {
+ promptingLock.wait();
+ } catch (final InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ if (autoClose) running = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (final IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /** @return the consoleManager */
+ public synchronized ConsoleManager getConsoleManager() {
+ return consoleManager;
+ }
+
+ /** @param app the application to set */
+ public synchronized void setApplication(ConsoleApplication app) {
+ this.app = app;
+ }
+
+}
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
new file mode 100644
index 0000000..a662c71
--- /dev/null
+++ b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/ConsoleTestApplication.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright E. Bigeon (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * Socket implementation of GCLC.
+ *
+ * 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.socket;
+
+import fr.bigeon.gclc.ConsoleApplication;
+import fr.bigeon.gclc.ConsoleManager;
+import fr.bigeon.gclc.command.Command;
+import fr.bigeon.gclc.exception.InvalidCommandName;
+
+/** TODO Describe ConsoleTestApplication.java
+ * @author Emmanuel Bigeon
+ *
+ */
+public class ConsoleTestApplication extends ConsoleApplication {
+
+ /** @param manager the manager */
+ @SuppressWarnings("nls")
+ public ConsoleTestApplication(final ConsoleManager manager) {
+ super(manager, "exit",
+ "Welcome to the test application. Type help or test.",
+ "See you");
+ addHelpCommand("help");
+ try {
+ add(new Command("test") {
+
+ @Override
+ public String tip() {
+ return "A test command";
+ }
+
+ @Override
+ public void execute(String... args) {
+ manager.println("Test command ran fine");
+ }
+ });
+ } catch (final InvalidCommandName e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestConsoleClient.java b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestConsoleClient.java
new file mode 100644
index 0000000..4119e7b
--- /dev/null
+++ b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestConsoleClient.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright E. Bigeon (2014)
+ *
+ * emmanuel@bigeon.fr
+ *
+ * This software is a computer program whose purpose is to
+ * Socket implementation of GCLC.
+ *
+ * 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.socket;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import fr.bigeon.smu.StringEncoder;
+
+/** TODO Describe TestConsoleClient.java
+ * @author Emmanuel Bigeon
+ *
+ */
+@SuppressWarnings("nls")
+public class TestConsoleClient {
+ @SuppressWarnings("javadoc")
+ private static final Collection
+ *
+ * @author Emmanuel Bigeon */
+public class SWTConsole extends Composite implements ConsoleManager, CommandRequestListener {
+ /** The cmd prefix in the output console */
+ private static final String CMD_PREFIX = "[CMD] "; //$NON-NLS-1$
+ /** The console output text field */
+ private final Text consoleOutput;
+ /** The console input text field */
+ private final Text consoleInput;
+ /** The prompt label */
+ private final Label lblPromptlabel;
+ /** The prompt text */
+ private String prompt = ">"; //$NON-NLS-1$
+ /** The command entered by the user */
+ private String command = null;
+ /** If the prompt should be active */
+ private boolean prompting = false;
+ /** The object for thread synchronization with the prompt */
+ private final Object promptLock = new Object();
+
+ /** The ribbon of commands */
+ private final Ribbon
+ *
+ * @author Emmanuel Bigeon */
+public class SWTConsoleShell extends Shell {
+
+ /** The console component */
+ private final SWTConsole console;
+
+ /** Create the shell.
+ *
+ * @param display the display */
+ public SWTConsoleShell(Display display) {
+ super(display, SWT.SHELL_TRIM);
+ setLayout(new FillLayout(SWT.HORIZONTAL));
+
+ console = new SWTConsole(this, SWT.NONE);
+ createContents();
+ }
+
+ /**
+ * Create contents of the shell.
+ */
+ protected void createContents() {
+ setText("Console Application"); //$NON-NLS-1$
+ setSize(450, 300);
+ }
+
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components
+ }
+
+ /** @return the console manager */
+ public ConsoleManager getManager() {
+ return console;
+ }
+
+ /** @return the element awaiting commands */
+ public CommandRequestListener getCommandListener() {
+ return console;
+ }
+}
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
new file mode 100644
index 0000000..15e96e8
--- /dev/null
+++ b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/AppTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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
+{
+ /**
+ * 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");
+// 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/pom.xml b/gclc/pom.xml
index 09d9d80..dbb199a 100644
--- a/gclc/pom.xml
+++ b/gclc/pom.xml
@@ -53,7 +53,7 @@
* 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 space.
+ *
+ * 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 default behavior for the brief message is to print the tip preceeded by a
+ * couple of spaces.
+ *
* @author Emmanuel BIGEON */
public abstract class Command {
+ /**
+ *
+ */
+ private static final String EOL_LINUX = "\n"; //$NON-NLS-1$
/** The name of the command */
protected final String name;
@@ -64,7 +84,19 @@ public abstract class Command {
/** @param args the arguments of the command (some expect an empty array) */
public abstract void execute(String... args);
- /** This prints the help associated to this command
+ /** This prints the help associated to this command.
+ *
+ * The default behavior is to print:
+ *
+ *
+ * This method return the detail of the help. It immediatly follows the
+ * {@link #usagePattern() usage pattern}.
+ *
+ * @return the detailed help (should end with end of line or be empty) */
@SuppressWarnings("static-method")
protected String usageDetail() {
return new String();
}
- /** @return the usage pattern */
+ /**
+ * This prints the usage pattern for the command. It follows the brief
+ * introduction on the command ({@link #brief()})
+ *
+ * @return the usage pattern */
protected String usagePattern() {
return getCommandName();
}
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 d0ca323..bc6245d 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/command/HelpExecutor.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/command/HelpExecutor.java
@@ -39,7 +39,6 @@
package fr.bigeon.gclc.command;
import fr.bigeon.gclc.ConsoleManager;
-import fr.bigeon.gclc.exception.InvalidCommandName;
import fr.bigeon.gclc.prompt.CLIPrompterMessages;
/**
@@ -55,15 +54,11 @@ public class HelpExecutor extends Command {
/** @param cmdName the command name
* @param consoleManager the manager for the console
- * @param cmd the command to execute the help of
- * @throws InvalidCommandName if the name is invalid */
- public HelpExecutor(String cmdName, ConsoleManager consoleManager,
- Command cmd) throws InvalidCommandName {
+ * @param cmd the command to execute the help of */
+ public HelpExecutor(String cmdName, ConsoleManager consoleManager, Command cmd) {
super(cmdName);
this.cmd = cmd;
- if (consoleManager == null)
- throw new NullPointerException(
- "Argument cannot be null: ConsoleManager"); //$NON-NLS-1$
+ if (consoleManager == null) throw new NullPointerException("Argument cannot be null: ConsoleManager"); //$NON-NLS-1$
this.consoleManager = consoleManager;
}
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 a5dc533..3f03cbc 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/prompt/CLIPrompter.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/prompt/CLIPrompter.java
@@ -55,6 +55,8 @@ public class CLIPrompter {
private static final String LIST_DISP_KEY = "promptlist.exit.dispkey"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
private static final String PROMPT = "prompt.lineprompt"; //$NON-NLS-1$
+ @SuppressWarnings("javadoc")
+ private static final String LIST_CHOICE_SEP = "promptlist.multi.sepkey"; //$NON-NLS-1$
/** @param manager the manager
* @param prompt the prompting message
@@ -268,10 +270,95 @@ public class CLIPrompter {
return choices.get(index);
}
+ /** @param manager the manager
+ * @param The choices labels type
+ * @param
+ *
+ *
+ * [Command name]
+ * [brief message]
+ *
+ * Usage:
+ * [Usage pattern]
+ *
+ * [Usage details]
+ *
*
* @param manager the manager to print the data
* @param args the arguments called with the help */
@@ -75,16 +107,30 @@ public abstract class Command {
manager.println("Usage:"); //$NON-NLS-1$
manager.println(usagePattern());
manager.println();
- manager.print(usageDetail());
+ String details = usageDetail();
+ if (details != null && !details.isEmpty()) {
+ manager.print(details);
+ if (!(details.endsWith(EOL_LINUX) || details.endsWith(System.lineSeparator()))) {
+ manager.println();
+ }
+ }
}
- /** @return the detailed help (should end with end of line or be empty) */
+ /**