From b24b72f3e243ad5ddcdeece1c9ee041554e1c71b Mon Sep 17 00:00:00 2001 From: Emmanuel Bigeon Date: Sun, 25 Nov 2018 11:05:00 -0500 Subject: [PATCH] Fixed console input Signed-off-by: Emmanuel Bigeon --- gclc-process/pom.xml | 6 ++ .../process/io/ConnectingConsoleInput.java | 99 +++++++++++-------- .../io/ConnectingConsoleInputTest.java | 72 ++++++++++++++ 3 files changed, 137 insertions(+), 40 deletions(-) diff --git a/gclc-process/pom.xml b/gclc-process/pom.xml index feeab46..d192386 100644 --- a/gclc-process/pom.xml +++ b/gclc-process/pom.xml @@ -51,6 +51,12 @@ gclc 2.0.11 + + net.bigeon.test + junitmt + 1.0.2 + test + diff --git a/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java b/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java index cf83ab3..04a5e97 100644 --- a/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java +++ b/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java @@ -120,15 +120,18 @@ public final class ConnectingConsoleInput implements ConsoleInput { public void connect(final ConsoleInput input) { disconnect(); synchronized (promptLock) { - connected = input; promptLock.notifyAll(); + synchronized (connectionLock) { + connected = input; + connectionLock.notifyAll(); + } } } /** Disconnect the current input. */ public void disconnect() { - synchronized (promptLock) { - synchronized (connectionLock) { + synchronized (connectionLock) { + synchronized (promptLock) { if (connected != null) { disconnection = true; connected.interruptPrompt(); @@ -149,12 +152,15 @@ public final class ConnectingConsoleInput implements ConsoleInput { * @see fr.bigeon.gclc.manager.ConsoleInput#interruptPrompt() */ @Override public void interruptPrompt() { - synchronized (promptLock) { - prompting = false; - if (connected != null) { - connected.interruptPrompt(); + synchronized (connectionLock) { + synchronized (promptLock) { + connectionLock.notifyAll(); + if (connected != null) { + connected.interruptPrompt(); + } + prompting = false; + promptLock.notifyAll(); } - promptLock.notifyAll(); } } @@ -191,27 +197,34 @@ public final class ConnectingConsoleInput implements ConsoleInput { if (!prompting) { return null; } - boolean connect; - synchronized (connectionLock) { - connect = connected != null; - } + } + boolean connect; + synchronized (connectionLock) { + connect = connected != null; if (!connect) { try { - promptLock.wait(); + connectionLock.wait(); } catch (final InterruptedException e) { LOGGER.log(Level.WARNING, "Inerruption of console thread", e); Thread.currentThread().interrupt(); } - } else { - synchronized (connectionLock) { - final String res = connected.prompt(message); - if (disconnection) { - disconnection = false; - } else if (prompting) { - return res; - } else { - // prompt interrupted, lose the result. - } + } + } + + ConsoleInput actualConnected; + synchronized (connectionLock) { + connect = connected != null; + actualConnected = connected; + } + if (connect) { + final String res = actualConnected.prompt(message); + synchronized (promptLock) { + if (disconnection) { + disconnection = false; + } else if (prompting) { + return res; + } else { + // prompt interrupted, lose the result. } } } @@ -234,33 +247,39 @@ public final class ConnectingConsoleInput implements ConsoleInput { if (!prompting) { return null; } - boolean connect; - synchronized (connectionLock) { - connect = connected != null; - } + } + boolean connect; + synchronized (connectionLock) { + connect = connected != null; if (!connect) { try { - promptLock.wait(timeout); + connectionLock.wait(timeout); } catch (final InterruptedException e) { - LOGGER.log(Level.WARNING, "Inerruption of console thread", e); Thread.currentThread().interrupt(); } - } else { - synchronized (connectionLock) { - final String res = connected.prompt(message, - end - System.currentTimeMillis()); - if (disconnection) { - disconnection = false; - } else if (prompting) { - return res; - } else { - // prompt interrupted, lose the result. - } + } + } + ConsoleInput actualConnected; + synchronized (connectionLock) { + connect = connected != null; + actualConnected = connected; + } + if (connect) { + synchronized (promptLock) { + final String res = actualConnected.prompt(message, + end - System.currentTimeMillis()); + if (disconnection) { + disconnection = false; + } else if (prompting) { + return res; + } else { + // prompt interrupted, lose the result. } } } } while (System.currentTimeMillis() < end); return null; + } /* (non-Javadoc) diff --git a/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java b/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java index 548a89d..632db2f 100644 --- a/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java +++ b/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java @@ -6,11 +6,20 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import net.bigeon.gclc.tools.ConstantString; import net.bigeon.gclc.utils.PipedConsoleInput; +import net.bigeon.gclc.utils.StreamConsoleInput; +import net.bigeon.test.junitmt.ATestRunnable; +import net.bigeon.test.junitmt.FunctionalTestRunnable; +import net.bigeon.test.junitmt.TestFunction; +import net.bigeon.test.junitmt.ThreadTest; public class ConnectingConsoleInputTest { @@ -62,4 +71,67 @@ public class ConnectingConsoleInputTest { in.setPrompt(prompt); assertEquals("Prompt should be set correctly", prompt, in.getPrompt()); } + + @Test + public void testPromptSequence() throws IOException, InterruptedException { + final ConnectingConsoleInput in = new ConnectingConsoleInput(); + // Unconnected + final AtomicBoolean ended = new AtomicBoolean(false); + final TestFunction one = new TestFunction() { + + @Override + public void apply() throws Exception { + assertNull(in.prompt("m1", -1)); + assertNull(in.prompt("m2", 5000)); + ended.set(true); + assertNull(in.prompt("m3", 200)); + } + }; + final ATestRunnable runnable = new FunctionalTestRunnable(one); + final Thread th = new Thread(runnable); + final Thread inter = new Thread(new Runnable() { + + @Override + public void run() { + while (!ended.get()) { + try { + th.join(500); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + in.interruptPrompt(); + } + } + }); + th.start(); + inter.start(); + ThreadTest.assertRuns(th, runnable); + inter.join(); + ended.set(false); + + final PipedOutputStream os = new PipedOutputStream(); + final PipedInputStream pis = new PipedInputStream(os); + in.connect(new StreamConsoleInput(System.out, pis, StandardCharsets.UTF_8)); + final ATestRunnable runnable2 = new FunctionalTestRunnable(one); + final Thread th2 = new Thread(runnable2); + final Thread inter2 = new Thread(new Runnable() { + + @Override + public void run() { + while (!ended.get()) { + try { + th2.join(500); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + in.interruptPrompt(); + } + } + }); + th2.start(); + inter2.start(); + ThreadTest.assertRuns(th2, runnable2); + } }