diff --git a/gclc-socket/pom.xml b/gclc-socket/pom.xml index 17df76f..dee7a8f 100644 --- a/gclc-socket/pom.xml +++ b/gclc-socket/pom.xml @@ -76,6 +76,7 @@ of Emmanuel Bigeon. --> http://www.bigeon.fr/emmanuel UTF-8 + git.bigeon.net @@ -87,7 +88,7 @@ of Emmanuel Bigeon. --> fr.bigeon gclc - 1.2.1 + 1.2.2 fr.bigeon @@ -102,4 +103,8 @@ of Emmanuel Bigeon. --> GCLC Socket Socket implementation of GCLC + + scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git + HEAD + diff --git a/gclc-socket/src/main/java/fr/bigeon/gclc/socket/SocketConsoleApplicationShell.java b/gclc-socket/src/main/java/fr/bigeon/gclc/socket/SocketConsoleApplicationShell.java index 7f9522b..77da3b0 100644 --- a/gclc-socket/src/main/java/fr/bigeon/gclc/socket/SocketConsoleApplicationShell.java +++ b/gclc-socket/src/main/java/fr/bigeon/gclc/socket/SocketConsoleApplicationShell.java @@ -142,34 +142,35 @@ public class SocketConsoleApplicationShell implements Runnable { * @see java.lang.Runnable#run() */ @Override public void run() { + // Create the server try (ServerSocket actualServerSocket = new ServerSocket(port)) { this.serverSocket = actualServerSocket; running = true; + // Create the streams try (PipedOutputStream outStream = new PipedOutputStream(); BufferedWriter writer = new BufferedWriter( - new OutputStreamWriter(outStream))) { + new OutputStreamWriter(outStream)); + InputStreamReader isr = new InputStreamReader(consoleInput); + BufferedReader inBuf = new BufferedReader(isr)) { consoleInput.connect(outStream); - try (InputStreamReader isr = new InputStreamReader( - consoleInput); - BufferedReader inBuf = new BufferedReader(isr);) { - consoleManager.setInput(inBuf); - runSokectServer(writer); - // Close the application - // Pass command to application - if (app.isRunning()) { - writer.write(applicationShutdown + EOL); - writer.flush(); - } + consoleManager.setInput(inBuf); + runSokectServer(writer); + // Close the application + // Pass command to application + if (app.isRunning()) { + writer.write(applicationShutdown + EOL); + writer.flush(); } } - } catch (final IOException e) { + } catch ( + + final IOException e) { LOGGER.log(Level.SEVERE, "Communication error between client and server", e); //$NON-NLS-1$ } } - /** @param appTh the application thread - * @param writer the writer to the application + /** @param writer the writer to the application * @throws IOException if the communication with the client failed */ private void runSokectServer(BufferedWriter writer) throws IOException { final ConsoleRunnable runnable = new ConsoleRunnable(app, diff --git a/gclc-swt/pom.xml b/gclc-swt/pom.xml index 0ac6fbb..849f736 100644 --- a/gclc-swt/pom.xml +++ b/gclc-swt/pom.xml @@ -51,7 +51,7 @@ fr.bigeon gclc - 1.2.1 + 1.2.2 org.eclipse.swt diff --git a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/HistoryTextKeyListener.java b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/HistoryTextKeyListener.java new file mode 100644 index 0000000..e5edaaa --- /dev/null +++ b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/HistoryTextKeyListener.java @@ -0,0 +1,111 @@ +/* + * 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. + */ +/** + * gclc-swt:fr.bigeon.gclc.swt.HistoryTextKeyListener.java + * Created on: Jun 9, 2016 + */ +package fr.bigeon.gclc.swt; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.widgets.Text; + +import fr.bigeon.collections.ArrayRibbon; +import fr.bigeon.collections.Ribbon; + +/** A key listener to validate commands and manage the history of commands + * + * @author Emmanuel Bigeon */ +public final class HistoryTextKeyListener extends KeyAdapter { + + /** The size of commands history */ + private static final int DEFAULT_HISTORY_SIZE = 10; + /** The history ribbon */ + private final Ribbon commands; + /** The current index in history search */ + private int currentIndex = 0; + /** The console to write the commands in */ + private final Text consoleInput; + /** The console to notify of command validation */ + private final SWTConsole console; + + /** @param console the console + * @param consoleInput the text to write commands in */ + public HistoryTextKeyListener(SWTConsole console, Text consoleInput) { + super(); + this.console = console; + this.consoleInput = consoleInput; + this.commands = new ArrayRibbon<>(DEFAULT_HISTORY_SIZE); + } + + @Override + public void keyPressed(KeyEvent e) { + + pressedKeyCode(e.keyCode); + } + + /** @param keyCode */ + public void pressedKeyCode(int keyCode) { + // Enter validates the command if prompting + if (keyCode == '\r') { + commands.add(consoleInput.getText()); + console.validateInput(); + currentIndex = -1; + } + + // Upper arrow retrieves previous commands + if (keyCode == SWT.ARROW_UP && + currentIndex < commands.size() - 1) { + currentIndex++; + String cmd = commands.get(commands.size() - currentIndex - 1); + consoleInput.setText(cmd); + consoleInput.setSelection(cmd.length()); + } + + // Lower arrow retrieves next commands + if (keyCode == SWT.ARROW_DOWN) { + if (currentIndex == 0) { + currentIndex--; + consoleInput.setText(new String()); + } else if (currentIndex > 0) { + String cmd = commands + .get(commands.size() - (--currentIndex) - 1); + consoleInput.setText(cmd); + consoleInput.setSelection(cmd.length()); + } + } + } +} \ No newline at end of file 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 6b2c692..3d6591a 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 @@ -39,12 +39,12 @@ package fr.bigeon.gclc.swt; import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.KeyAdapter; -import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; @@ -52,8 +52,6 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; -import fr.bigeon.collections.ArrayRibbon; -import fr.bigeon.collections.Ribbon; import fr.bigeon.gclc.ConsoleApplication; import fr.bigeon.gclc.manager.ConsoleManager; @@ -62,70 +60,15 @@ import fr.bigeon.gclc.manager.ConsoleManager; * * @author Emmanuel Bigeon */ public class SWTConsole extends Composite implements ConsoleManager { - /** A key listener to validate commands and manage the history of commands - * - * @author Emmanuel Bigeon */ - public static final class HistoryTextKeyListener extends KeyAdapter { - - /** The size of commands history */ - private static final int DEFAULT_HISTORY_SIZE = 10; - /** The history ribbon */ - private final Ribbon commands; - /** The current index in history search */ - private int currentIndex = 0; - /** The console to write the commands in */ - private final Text consoleInput; - /** The console to notify of command validation */ - private final SWTConsole console; - - /** @param console the console - * @param consoleInput the text to write commands in */ - public HistoryTextKeyListener(SWTConsole console, Text consoleInput) { - super(); - this.console = console; - this.consoleInput = consoleInput; - this.commands = new ArrayRibbon<>(DEFAULT_HISTORY_SIZE); - } - - @Override - public void keyPressed(KeyEvent e) { - // Enter validates the command if prompting - if (e.keyCode == '\r') { - commands.add(consoleInput.getText()); - console.validateInput(); - currentIndex = -1; - } - - // Upper arrow retrieves previous commands - if (e.keyCode == SWT.ARROW_UP && - currentIndex < commands.size() - 1) { - currentIndex++; - String cmd = commands.get(commands.size() - currentIndex - 1); - consoleInput.setText(cmd); - consoleInput.setSelection(cmd.length()); - } - - // Lower arrow retrieves next commands - if (e.keyCode == SWT.ARROW_DOWN) { - if (currentIndex == 0) { - currentIndex--; - consoleInput.setText(new String()); - } else if (currentIndex > 0) { - String cmd = commands - .get(commands.size() - (--currentIndex) - 1); - consoleInput.setText(cmd); - consoleInput.setSelection(cmd.length()); - } - } - } - } - /** * */ private static final int LAYOUT_NB_COLUMNS = 2; /** The cmd prefix in the output console */ private static final String CMD_PREFIX = "[CMD] "; //$NON-NLS-1$ + /** The class logger */ + private static final Logger LOGGER = Logger + .getLogger(SWTConsole.class.getName()); /** The console output text field */ private final Text consoleOutput; /** The console input text field */ @@ -169,8 +112,8 @@ public class SWTConsole extends Composite implements ConsoleManager { consoleInput = new Text(this, SWT.BORDER); consoleInput.setLayoutData( new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - consoleInput.addKeyListener( - new HistoryTextKeyListener(this, consoleInput)); + consoleInput + .addKeyListener(new HistoryTextKeyListener(this, consoleInput)); } @@ -178,16 +121,34 @@ public class SWTConsole extends Composite implements ConsoleManager { * */ protected void validateInput() { - if (prompting) { - synchronized (promptLock) { - command = consoleInput.getText(); - prompting = false; - consoleInput.setText(new String()); + Display.getDefault().syncExec(new Runnable() { + @SuppressWarnings("synthetic-access") + @Override + public void run() { consoleInput.setEnabled(false); - consoleOutput - .append(CMD_PREFIX + command + System.lineSeparator()); - promptLock.notifyAll(); } + }); + synchronized (promptLock) { + while (!prompting) { + try { + promptLock.wait(); + } catch (InterruptedException e) { + LOGGER.log(Level.SEVERE, + "Interruption while waiting prompt", e); //$NON-NLS-1$ + } + } + Display.getDefault().syncExec(new Runnable() { + @SuppressWarnings("synthetic-access") + @Override + public void run() { + command = consoleInput.getText(); + prompting = false; + consoleInput.setText(new String()); + consoleOutput.append( + CMD_PREFIX + command + System.lineSeparator()); + } + }); + promptLock.notifyAll(); } } @@ -261,11 +222,15 @@ public class SWTConsole extends Composite implements ConsoleManager { } }); prompting = true; + promptLock.notifyAll(); promptLock.wait(); } catch (final InterruptedException e) { command = null; } } + if (isDisposed()) { + throw new IOException("Input closed"); //$NON-NLS-1$ + } return command; } @@ -355,4 +320,16 @@ public class SWTConsole extends Composite implements ConsoleManager { return isDisposed(); } + /** @param string the text */ + public void setText(String string) { + consoleInput.setText(string); + } + + /** + * + */ + public void validateCommand() { + validateInput(); + } + } diff --git a/gclc-swt/src/test/java/fr/bigeon/gclc/swt/HistoryTextKeyListenerTest.java b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/HistoryTextKeyListenerTest.java new file mode 100644 index 0000000..1dcf125 --- /dev/null +++ b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/HistoryTextKeyListenerTest.java @@ -0,0 +1,57 @@ +/* + * 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. + */ +/** + * gclc-swt:fr.bigeon.gclc.swt.HistoryTextKeyListenerTest.java + * Created on: Jun 9, 2016 + */ +package fr.bigeon.gclc.swt; + +import org.junit.Test; + +/** + *

+ * TODO + * + * @author Emmanuel Bigeon + * + */ +public class HistoryTextKeyListenerTest { + + @Test + public void test() { + + } + +} 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 index a50849c..5516c54 100644 --- a/gclc-swt/src/test/java/fr/bigeon/gclc/swt/SWTConsoleShellTest.java +++ b/gclc-swt/src/test/java/fr/bigeon/gclc/swt/SWTConsoleShellTest.java @@ -41,30 +41,159 @@ package fr.bigeon.gclc.swt; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.IOException; + 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.CommandRunException; import fr.bigeon.gclc.exception.InvalidCommandName; -import fr.bigeon.gclc.manager.ConsoleManager; -/** - *

+/**

* TODO * - * @author Emmanuel Bigeon - * - */ + * @author Emmanuel Bigeon */ public class SWTConsoleShellTest { protected static final long TWO_SECONDS = 2000; + private static final Display DISPLAY = new Display(); + + @Test + public void testConsoleClose() { + final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY); + final SWTConsole swtConsole = (SWTConsole) shell.getManager(); + swtConsole.close(); + swtConsole.setPrompt(":"); + 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(); + } + } + }); + appl.add(new Command("test") { + + @Override + public String tip() { + return "a prompting running command"; + } + + @Override + public void execute(String... args) throws CommandRunException { + try { + appl.getManager().prompt("Test"); + } catch (IOException e) { + throw new CommandRunException("No input", e); + } + } + }); +// 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() { + swtConsole.setText("test"); //$NON-NLS-1$ + swtConsole.validateCommand(); + } + }); + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + swtConsole.setText("ok"); //$NON-NLS-1$ + } + }); + swtConsole.validateCommand(); + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + swtConsole.setText("long"); //$NON-NLS-1$ + } + }); + swtConsole.validateCommand(); + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + swtConsole.setText("test"); //$NON-NLS-1$ + } + }); + swtConsole.validateCommand(); + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + swtConsole.setText("test"); //$NON-NLS-1$ + } + }); + swtConsole.validateCommand(); + 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(); + } + } @Test public void test() { - Display display = new Display(); - final SWTConsoleShell shell = new SWTConsoleShell(display); - ConsoleManager swtConsole = shell.getManager(); + final SWTConsoleShell shell = new SWTConsoleShell(DISPLAY); + final SWTConsole swtConsole = (SWTConsole) shell.getManager(); try { final ConsoleApplication appl = new ConsoleApplication(swtConsole, "exit", "Hello", "See you"); @@ -98,6 +227,19 @@ public class SWTConsoleShellTest { @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() { + swtConsole.setText("test"); //$NON-NLS-1$ + swtConsole.validateCommand(); + } + }); try { Thread.sleep(TWO_SECONDS); } catch (InterruptedException e) { @@ -115,11 +257,11 @@ public class SWTConsoleShellTest { applThread.start(); testThread.start(); while (!shell.isDisposed()) { - if (!display.readAndDispatch()) { - display.sleep(); + if (!DISPLAY.readAndDispatch()) { + DISPLAY.sleep(); } } -// display.dispose(); +// DISPLAY.dispose(); assertTrue(appl.getManager().isClosed()); Thread.sleep(TWO_SECONDS); assertFalse(appl.isRunning()); diff --git a/gclc/pom.xml b/gclc/pom.xml index b0fdfda..7c30006 100644 --- a/gclc/pom.xml +++ b/gclc/pom.xml @@ -35,7 +35,7 @@ 4.0.0 gclc - 1.2.2-SNAPSHOT + 1.2.3-SNAPSHOT jar http://www.bigeon.fr/emmanuel