Fixed console input

Signed-off-by: Emmanuel Bigeon <emmanuel@bigeon.fr>
This commit is contained in:
Emmanuel Bigeon 2018-11-25 11:05:00 -05:00
parent ad79e3ccb6
commit b24b72f3e2
3 changed files with 137 additions and 40 deletions

View File

@ -51,6 +51,12 @@
<artifactId>gclc</artifactId>
<version>2.0.11</version>
</dependency>
<dependency>
<groupId>net.bigeon.test</groupId>
<artifactId>junitmt</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<reporting>
<plugins>

View File

@ -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)

View File

@ -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);
}
}