diff --git a/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ConsoleRunnable.java b/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ConsoleRunnable.java index 2a6d2ea..9ff565e 100644 --- a/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ConsoleRunnable.java +++ b/gclc-socket/src/main/java/fr/bigeon/gclc/socket/ConsoleRunnable.java @@ -44,7 +44,7 @@ import fr.bigeon.gclc.ConsoleApplication; * * @author Emmanuel Bigeon */ public class ConsoleRunnable implements Runnable { - + /** The actual application */ private final ConsoleApplication app; /** The synchronization object */ @@ -74,4 +74,9 @@ public class ConsoleRunnable implements Runnable { app.exit(); } + /** @return if the application is running */ + public boolean isRunning() { + return app.isRunning(); + } + } 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 5bd2577..f7ef0e3 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 @@ -110,7 +110,7 @@ public class SocketConsoleApplicationShell implements Runnable { /** The application shutdown string */ private final String applicationShutdown; /** The charset for the communication. */ - private Charset charset; + private final Charset charset; /** Create a socket application shell which will listen on the given port * and close session upon the provided string reception by client @@ -156,8 +156,7 @@ public class SocketConsoleApplicationShell implements Runnable { // Create the streams try (PipedOutputStream outStream = new PipedOutputStream(); BufferedWriter writer = new BufferedWriter( - new OutputStreamWriter(outStream, - charset)); + new OutputStreamWriter(outStream, charset)); InputStreamReader isr = new InputStreamReader(consoleInput, charset); BufferedReader inBuf = new BufferedReader(isr)) { @@ -187,24 +186,24 @@ public class SocketConsoleApplicationShell implements Runnable { Thread appThOld = null; Thread appThNext = new Thread(runnable); while (running) { + LOGGER.info("Opening client"); //$NON-NLS-1$ try (Socket clientSocket = serverSocket.accept(); - PrintWriter out = new PrintWriter( - new OutputStreamWriter(clientSocket.getOutputStream(), - charset), - true); + PrintWriter out = new PrintWriter(new OutputStreamWriter( + clientSocket.getOutputStream(), charset), true); InputStreamReader isr = new InputStreamReader( - clientSocket.getInputStream(), - charset); + clientSocket.getInputStream(), charset); BufferedReader in = new BufferedReader(isr);) { // this is not threaded to avoid several clients at the same // time consoleManager.setOutput(out); // Initiate application - if (appThOld == null || !appThOld.isAlive()) { + + if (appThOld == null || !appThOld.isAlive() || + !runnable.isRunning()) { appThNext.start(); // Prepare next start appThOld = appThNext; - appThNext = new Thread(runnable); + appThNext = new Thread(runnable, "gclc-ctrl"); //$NON-NLS-1$ } else { out.println("Reconnected"); //$NON-NLS-1$ } @@ -215,7 +214,9 @@ public class SocketConsoleApplicationShell implements Runnable { "Socket closed with exception (probably due to server interruption)", //$NON-NLS-1$ e); } + LOGGER.info("Closing client"); //$NON-NLS-1$ } + LOGGER.info("Out client"); //$NON-NLS-1$ } /** active communication between server and client diff --git a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/SocketConsoleApplicationTest.java b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/SocketConsoleApplicationTest.java index bb13883..4f66691 100644 --- a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/SocketConsoleApplicationTest.java +++ b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/SocketConsoleApplicationTest.java @@ -38,6 +38,9 @@ */ package fr.bigeon.gclc.socket; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -60,7 +63,8 @@ public class SocketConsoleApplicationTest { @Test public void integrationTest() { - Thread server = TestServer.startServer(false); + Thread server; + server = TestServer.startServer("bye"); try { Thread.sleep(100); } catch (InterruptedException e1) { @@ -70,27 +74,89 @@ public class SocketConsoleApplicationTest { final int portNumber = 3300; try (Socket kkSocket = new Socket(hostName, portNumber); - PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), - true); - BufferedReader in = new BufferedReader( - new InputStreamReader(kkSocket.getInputStream()));) { + PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), + true); + BufferedReader in = new BufferedReader( + new InputStreamReader(kkSocket.getInputStream()));) { String fromServer; int i = 0; - String[] cmds = {"help", "toto", "test", "close"}; + String[] cmds = {"help", "toto", "test", "bye"}; while ((fromServer = in.readLine()) != null) { - System.out.println("Server: \n" + ENCODER.decode(fromServer)); +// System.out.println("Server: \n" + ENCODER.decode(fromServer)); if (fromServer.equals("Bye.")) { break; } final String fromUser = cmds[i]; if (fromUser != null) { - System.out.println("Client: " + fromUser); +// System.out.println("Client: " + fromUser); out.println(fromUser); } i++; } + assertEquals(4, i); + } catch (final IOException e) { + e.printStackTrace(); + } + + try (Socket kkSocket = new Socket(hostName, portNumber); + PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), + true); + BufferedReader in = new BufferedReader( + new InputStreamReader(kkSocket.getInputStream()));) { + + String fromServer; + int i = 0; + String[] cmds = {"help", "toto", "test", + ConsoleTestApplication.EXIT}; + while ((fromServer = in.readLine()) != null) { +// System.out.println("Server: \n" + ENCODER.decode(fromServer)); + if (fromServer.equals("Bye.")) { + break; + } + + final String fromUser = cmds[i]; + if (fromUser != null) { +// System.out.println("Client: " + fromUser); + out.println(fromUser); + } + i++; + } + assertEquals(4, i); + } catch (final IOException e) { + e.printStackTrace(); + } + try { + Thread.sleep(100); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + + try (Socket kkSocket = new Socket(hostName, portNumber); + PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), + true); + BufferedReader in = new BufferedReader( + new InputStreamReader(kkSocket.getInputStream()));) { + + String fromServer; + int i = 0; + String[] cmds = {"help", "toto", "test", + ConsoleTestApplication.EXIT}; + while ((fromServer = in.readLine()) != null) { +// System.out.println("Server: \n" + ENCODER.decode(fromServer)); + if (fromServer.equals("Bye.")) { + break; + } + + final String fromUser = cmds[i]; + if (fromUser != null) { +// System.out.println("Client: " + fromUser); + out.println(fromUser); + } + i++; + } + assertEquals(4, i); } catch (final IOException e) { e.printStackTrace(); } @@ -108,31 +174,39 @@ public class SocketConsoleApplicationTest { } try (Socket kkSocket = new Socket(hostName, portNumber); - PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), - true); - BufferedReader in = new BufferedReader( - new InputStreamReader(kkSocket.getInputStream()));) { + PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), + true); + BufferedReader in = new BufferedReader( + new InputStreamReader(kkSocket.getInputStream()));) { String fromServer; int i = 0; String[] cmds = {"help", "test", "close"}; while ((fromServer = in.readLine()) != null) { -// System.out.println("Server: \n" + ENCODER.decode(fromServer)); + assertTrue(i < 2); + System.out.println("Server: \n" + ENCODER.decode(fromServer)); if (fromServer.equals("Bye.")) { break; } final String fromUser = cmds[i]; if (fromUser != null) { -// System.out.println("Client: " + fromUser); + System.out.println("Client: " + fromUser); out.println(fromUser); } i++; } + assertEquals(2, i); } catch (final IOException e) { e.printStackTrace(); } + Thread srv = TestServer.getServer(); TestServer.closeServer(); - + try { + srv.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } diff --git a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestServer.java b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestServer.java index 465767c..4a4b144 100644 --- a/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestServer.java +++ b/gclc-socket/src/test/java/fr/bigeon/gclc/socket/TestServer.java @@ -85,6 +85,18 @@ public class TestServer { return getServer(); } + public static Thread startServer(String closeConnection) { + if (SHELL == null) { + SHELL = new SocketConsoleApplicationShell(3300, closeConnection, + ConsoleTestApplication.EXIT, Charset.forName("UTF-8")); + final ConsoleTestApplication app = new ConsoleTestApplication( + SHELL.getConsoleManager()); + SHELL.setApplication(app); + server = null; + } + return getServer(); + } + public static void closeServer() { SHELL.stop(); SHELL = null; diff --git a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/ConsoleDelayIO.java b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/ConsoleDelayIO.java index abb7c08..51630e4 100644 --- a/gclc-swt/src/main/java/fr/bigeon/gclc/swt/ConsoleDelayIO.java +++ b/gclc-swt/src/main/java/fr/bigeon/gclc/swt/ConsoleDelayIO.java @@ -40,13 +40,13 @@ package fr.bigeon.gclc.swt; import fr.bigeon.gclc.manager.ConsoleManager; -/** +/** This class represents an object used to send commands to a console + * application. *
- * TODO + * The sending of command is done in two phases. Define the input through get + * and set, and then validate the input. * - * @author Emmanuel Bigeon - * - */ + * @author Emmanuel Bigeon */ public interface ConsoleDelayIO extends ConsoleManager { /** Actually send the input as the prompt next input. */ void validateInput(); diff --git a/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java b/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java index 78473b7..c720d3d 100644 --- a/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java +++ b/gclc/src/main/java/fr/bigeon/gclc/ConsoleApplication.java @@ -37,6 +37,7 @@ package fr.bigeon.gclc; import java.io.IOException; +import java.io.InterruptedIOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -106,18 +107,13 @@ public class ConsoleApplication implements ICommandProvider { return root.add(cmd); } - /** Add a command request listener. - *
- * A listener can listen several times to the same application.
- *
- * @param listener the listener to add. */
+ /** @param listener the command listener */
public final void addListener(CommandRequestListener listener) {
listeners.add(listener);
}
/* (non-Javadoc)
- * @see
- * fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
+ * @see fr.bigeon.gclc.command.ICommandProvider#executeSub(java.lang.String,
* java.lang.String[]) */
@Override
public final void executeSub(String command,
@@ -125,10 +121,11 @@ public class ConsoleApplication implements ICommandProvider {
root.executeSub(command, args);
}
- /** Exit this running application before next command prompt */
+ /** Signify to the application that no command should be inputed anymore */
public final void exit() {
LOGGER.fine("Request exiting application..."); //$NON-NLS-1$
running = false;
+ manager.interruptPrompt();
}
/* (non-Javadoc)
@@ -143,8 +140,8 @@ public class ConsoleApplication implements ICommandProvider {
return manager;
}
- /** @param cmd the command to interpret
- * @throws IOException if the manager was closed */
+ /** @param cmd the command
+ * @throws IOException if the command could not be parsed */
public final void interpretCommand(String cmd) throws IOException {
List
* A console manager is in charge of the basic prompts and prints on a console.
@@ -69,15 +70,15 @@ public interface ConsoleManager {
void println(String message) throws IOException;
/** @return the user inputed string
- * @throws IOException if the manager is closed or could not read the
- * prompt */
- String prompt() throws IOException;
+ * @throws IOException if the manager is closed or could not read the prompt
+ * @throws InterruptedIOException if the prompt was interrupted */
+ String prompt() throws IOException, InterruptedIOException;
/** @param message the message to prompt the user
* @return the user inputed string
- * @throws IOException if the manager is closed or could not read the
- * prompt */
- String prompt(String message) throws IOException;
+ * @throws IOException if the manager is closed or could not read the prompt
+ * @throws InterruptedIOException if the prompt was interrupted */
+ String prompt(String message) throws IOException, InterruptedIOException;
/**
* Set a prompting prefix.
@@ -92,4 +93,7 @@ public interface ConsoleManager {
/** @return if the manager is closed. */
boolean isClosed();
+
+ /** Indicate to the manager that is should interrompt the prompting */
+ void interruptPrompt();
}
diff --git a/gclc/src/main/java/fr/bigeon/gclc/manager/ReadRunnable.java b/gclc/src/main/java/fr/bigeon/gclc/manager/ReadRunnable.java
new file mode 100644
index 0000000..8515de3
--- /dev/null
+++ b/gclc/src/main/java/fr/bigeon/gclc/manager/ReadRunnable.java
@@ -0,0 +1,54 @@
+/**
+ * gclc:fr.bigeon.gclc.manager.ReadRunnable.java
+ * Created on: Nov 21, 2016
+ */
+package fr.bigeon.gclc.manager;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * TODO
+ *
+ * @author Emmanuel Bigeon
+ *
+ */
+public class ReadRunnable implements Runnable {
+
+ /** The logger */
+ private static final Logger LOGGER = Logger
+ .getLogger(ReadRunnable.class.getName());
+ /** The result */
+ private String result = "";
+ /** The input buffer */
+ private final BufferedReader in;
+
+ /** @param in the input buffer */
+ protected ReadRunnable(BufferedReader in) {
+ super();
+ this.in = in;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run() */
+ @Override
+ public void run() {
+ try {
+ result = in.readLine();
+ while (result != null && result.length() > 0 &&
+ result.charAt(0) == 0) {
+ result = result.substring(1);
+ }
+ } catch (final IOException e) {
+ LOGGER.log(Level.SEVERE, "Unable to read prompt", e); //$NON-NLS-1$
+ }
+ }
+
+ /** @return the result */
+ public String getResult() {
+ return result;
+ }
+}
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 0151454..b785a1f 100644
--- a/gclc/src/main/java/fr/bigeon/gclc/manager/SystemConsoleManager.java
+++ b/gclc/src/main/java/fr/bigeon/gclc/manager/SystemConsoleManager.java
@@ -44,7 +44,6 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.Charset;
-import java.util.logging.Level;
import java.util.logging.Logger;
/** A console using the input stream and print stream.
@@ -75,6 +74,8 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
/** If the manager is closed */
private boolean closed = false;
+ private Thread reading;
+
/** This default constructor relies on the system defined standart output
* and input stream. */
public SystemConsoleManager() {
@@ -140,18 +141,24 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
@Override
public String prompt(String message) throws IOException {
checkOpen();
- String result = EMPTY;
out.print(message);
- try {
+// ReadRunnable rr = new ReadRunnable(in);
+// reading = new Thread(rr, "prompt"); //$NON-NLS-1$
+// reading.start();
+// try {
+// reading.join();
+// } catch (final InterruptedException e) {
+// LOGGER.log(Level.SEVERE, "Prompt reading interrupted", e); //$NON-NLS-1$
+// throw new InterruptedIOException("Prompt interruption"); //$NON-NLS-1$
+// }
+ String result = EMPTY;
result = in.readLine();
while (result != null && result.length() > 0 &&
result.charAt(0) == 0) {
result = result.substring(1);
}
- } catch (final IOException e) {
- LOGGER.log(Level.SEVERE, "Unable to read prompt", e); //$NON-NLS-1$
- }
return result;
+// return rr.getResult();
}
/** @param prompt the prompt to set */
@@ -174,4 +181,13 @@ public class SystemConsoleManager implements ConsoleManager { // NOSONAR
return closed;
}
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
+ @Override
+ public void interruptPrompt() {
+ if (reading != null) {
+ reading.interrupt();
+ }
+ }
+
}
diff --git a/gclc/src/test/java/fr/bigeon/gclc/test/utils/TestConsoleManager.java b/gclc/src/test/java/fr/bigeon/gclc/test/utils/TestConsoleManager.java
index 29f23bb..e050b83 100644
--- a/gclc/src/test/java/fr/bigeon/gclc/test/utils/TestConsoleManager.java
+++ b/gclc/src/test/java/fr/bigeon/gclc/test/utils/TestConsoleManager.java
@@ -74,7 +74,7 @@ public class TestConsoleManager implements ConsoleManager, AutoCloseable {
PipedOutputStream out = new PipedOutputStream(commandOutput);
commandBuffOutput = new BufferedReader(
new InputStreamReader(commandOutput, Charset.defaultCharset()));
- outPrint = new PrintStream(out);
+ outPrint = new PrintStream(out, true, Charset.defaultCharset().name());
innerManager = new SystemConsoleManager(outPrint, in,
Charset.forName("UTF-8"));
}
@@ -141,4 +141,11 @@ public class TestConsoleManager implements ConsoleManager, AutoCloseable {
public String readNextLine() throws IOException {
return commandBuffOutput.readLine();
}
+
+ /* (non-Javadoc)
+ * @see fr.bigeon.gclc.manager.ConsoleManager#interruptPrompt() */
+ @Override
+ public void interruptPrompt() {
+ innerManager.interruptPrompt();
+ }
}