Compare commits
11 Commits
gclc-2.1.0
...
process-0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 314db5b82f | |||
| 981668d3a7 | |||
| 9c8866827d | |||
| 43c9faaee7 | |||
| 8436e8926c | |||
| 0cef23e17b | |||
| 6b2a25674d | |||
| eec660e089 | |||
| 901469792d | |||
| 79ee5394d4 | |||
| acf4484eb3 |
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<groupId>net.bigeon.gclc</groupId>
|
<groupId>net.bigeon.gclc</groupId>
|
||||||
<artifactId>process</artifactId>
|
<artifactId>process</artifactId>
|
||||||
<version>0.0.6-SNAPSHOT</version>
|
<version>0.0.6</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>process</name>
|
<name>process</name>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</developer>
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
<scm>
|
<scm>
|
||||||
<tag>HEAD</tag>
|
<tag>process-0.0.6</tag>
|
||||||
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||||
</scm>
|
</scm>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.bigeon</groupId>
|
<groupId>net.bigeon</groupId>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>2.0.12</version>
|
<version>2.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.bigeon.test</groupId>
|
<groupId>net.bigeon.test</groupId>
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ package net.bigeon.gclc.process.io;
|
|||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import net.bigeon.gclc.manager.ConsoleInput;
|
import net.bigeon.gclc.manager.ConsoleInput;
|
||||||
@@ -82,25 +83,27 @@ public final class ConnectingConsoleInput implements ConsoleInput {
|
|||||||
private static final ConstantString EMPTY_STRING = new ConstantString("");
|
private static final ConstantString EMPTY_STRING = new ConstantString("");
|
||||||
|
|
||||||
/** If the input is closed. */
|
/** If the input is closed. */
|
||||||
private boolean close = false;
|
private boolean close = false;
|
||||||
/** The prompt string. */
|
/** The prompt string. */
|
||||||
private Supplier<String> prompt = EMPTY_STRING;
|
private Supplier<String> prompt = EMPTY_STRING;
|
||||||
/** If the input is currently in prompting state.
|
/** If the input is currently in prompting state.
|
||||||
* <p>
|
* <p>
|
||||||
* To change it you should be in a promptLock. */
|
* To change it you should be in a promptLock. */
|
||||||
private boolean prompting = false;
|
private boolean prompting = false;
|
||||||
/** The synchronization lock for the prompting status. */
|
/** The synchronization lock for the prompting status. */
|
||||||
private final Object promptLock = new Object();
|
private final Object promptLock = new Object();
|
||||||
/** The synchronization lock for the connection status. */
|
/** The synchronization lock for the connection status. */
|
||||||
private final Object connectionLock = new Object();
|
private final Object connectionLock = new Object();
|
||||||
/** The connected console input.
|
/** The connected console input.
|
||||||
* <p>
|
* <p>
|
||||||
* To use it, you should be in a promptLock and connectionLock. */
|
* To use it, you should be in a promptLock and connectionLock. */
|
||||||
private ConsoleInput connected = null;
|
private ConsoleInput connected = null;
|
||||||
/** The connection state.
|
/** The connection state.
|
||||||
* <p>
|
* <p>
|
||||||
* To read or modify it, you should be in a connectionLock synchronize block. */
|
* To read or modify it, you should be in a connectionLock synchronize block. */
|
||||||
private boolean disconnection = false;
|
private boolean disconnection = false;
|
||||||
|
|
||||||
|
private boolean interrupting = false;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see fr.bigeon.gclc.manager.ConsoleInput#close() */
|
* @see fr.bigeon.gclc.manager.ConsoleInput#close() */
|
||||||
@@ -149,6 +152,9 @@ public final class ConnectingConsoleInput implements ConsoleInput {
|
|||||||
public void interruptPrompt() {
|
public void interruptPrompt() {
|
||||||
synchronized (connectionLock) {
|
synchronized (connectionLock) {
|
||||||
synchronized (promptLock) {
|
synchronized (promptLock) {
|
||||||
|
if (prompting) {
|
||||||
|
interrupting = true;
|
||||||
|
}
|
||||||
connectionLock.notifyAll();
|
connectionLock.notifyAll();
|
||||||
if (connected != null) {
|
if (connected != null) {
|
||||||
connected.interruptPrompt();
|
connected.interruptPrompt();
|
||||||
@@ -187,32 +193,7 @@ public final class ConnectingConsoleInput implements ConsoleInput {
|
|||||||
synchronized (promptLock) {
|
synchronized (promptLock) {
|
||||||
prompting = true;
|
prompting = true;
|
||||||
}
|
}
|
||||||
while (true) {
|
return doPrompt(message, 0, 0);
|
||||||
synchronized (promptLock) {
|
|
||||||
if (!prompting) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getConnection(0);
|
|
||||||
boolean connect;
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -222,42 +203,89 @@ public final class ConnectingConsoleInput implements ConsoleInput {
|
|||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
return prompt(message);
|
return prompt(message);
|
||||||
}
|
}
|
||||||
final long end = System.currentTimeMillis() + timeout;
|
|
||||||
synchronized (promptLock) {
|
synchronized (promptLock) {
|
||||||
prompting = true;
|
prompting = true;
|
||||||
}
|
}
|
||||||
|
final long tic = System.currentTimeMillis();
|
||||||
|
return doPrompt(message, timeout, tic);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String doPrompt(final String message, final long timeout, final long tic)
|
||||||
|
throws IOException {
|
||||||
do {
|
do {
|
||||||
synchronized (promptLock) {
|
if (!checkPrompt()) {
|
||||||
if (!prompting) {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
getConnection(timeout);
|
getConnection(getTimeoutLeft(tic, timeout));
|
||||||
boolean connect;
|
boolean connect;
|
||||||
ConsoleInput actualConnected;
|
ConsoleInput actualConnected;
|
||||||
synchronized (connectionLock) {
|
synchronized (connectionLock) {
|
||||||
connect = connected != null;
|
connect = connected != null;
|
||||||
actualConnected = connected;
|
actualConnected = connected;
|
||||||
}
|
}
|
||||||
if (connect) {
|
if (!connect) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final String res = actualPrompt(message, timeout, tic, actualConnected);
|
||||||
synchronized (promptLock) {
|
synchronized (promptLock) {
|
||||||
final String res = actualConnected.prompt(message,
|
if (prompting) {
|
||||||
end - System.currentTimeMillis());
|
prompting = false;
|
||||||
if (disconnection) {
|
|
||||||
disconnection = false;
|
|
||||||
} else if (prompting) {
|
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
// prompt interrupted, lose the result.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (final InterruptedIOException e) {
|
||||||
|
// The inner console was interrupted. This can mean we are
|
||||||
|
// disconnecting or actually interrupted.
|
||||||
|
if (disconnection) {
|
||||||
|
disconnection = false;
|
||||||
|
} else {
|
||||||
|
interrupting = false;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (System.currentTimeMillis() < end);
|
} while (checkTimeout(tic, timeout));
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getConnection(final long timeout) {
|
private static String actualPrompt(final String message, final long timeout,
|
||||||
|
final long tic, final ConsoleInput actualConnected) throws IOException {
|
||||||
|
final long timeoutLeft = getTimeoutLeft(tic, timeout);
|
||||||
|
if (timeoutLeft == 0) {
|
||||||
|
return actualConnected.prompt(message);
|
||||||
|
}
|
||||||
|
return actualConnected.prompt(message, timeoutLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkTimeout(final long tic, final long timeout) {
|
||||||
|
return timeout <= 0 || tic + timeout > System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getTimeoutLeft(final long tic, final long timeout) {
|
||||||
|
if (timeout > 0) {
|
||||||
|
return Math.max(timeout + tic - System.currentTimeMillis(), 1);
|
||||||
|
}
|
||||||
|
if (timeout < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test if we are in prompting state.
|
||||||
|
*
|
||||||
|
* @return if the process is currently in prompting state.
|
||||||
|
* @throws InterruptedIOException if the prompting state has been interrupted */
|
||||||
|
private boolean checkPrompt() throws InterruptedIOException {
|
||||||
|
synchronized (promptLock) {
|
||||||
|
if (!prompting && interrupting) {
|
||||||
|
interrupting = false;
|
||||||
|
throw new InterruptedIOException("Prompt was interrupted");
|
||||||
|
}
|
||||||
|
return prompting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getConnection(final long timeout) throws InterruptedIOException {
|
||||||
boolean connect;
|
boolean connect;
|
||||||
synchronized (connectionLock) {
|
synchronized (connectionLock) {
|
||||||
connect = connected != null;
|
connect = connected != null;
|
||||||
@@ -268,6 +296,10 @@ public final class ConnectingConsoleInput implements ConsoleInput {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (interrupting) {
|
||||||
|
interrupting = false;
|
||||||
|
throw new InterruptedIOException("Prompt ws interrupted");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,18 @@ package net.bigeon.gclc.process;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import net.bigeon.gclc.exception.CommandRunException;
|
import net.bigeon.gclc.exception.CommandRunException;
|
||||||
import net.bigeon.gclc.exception.CommandRunExceptionType;
|
import net.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
import net.bigeon.gclc.utils.PipedConsoleInput;
|
import net.bigeon.gclc.manager.PipedConsoleInput;
|
||||||
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
import net.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
/** @author Emmanuel Bigeon */
|
/** @author Emmanuel Bigeon */
|
||||||
public class ForkTaskTest {
|
public class ForkTaskTest {
|
||||||
@@ -36,15 +39,11 @@ public class ForkTaskTest {
|
|||||||
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
||||||
"Unable to prompt user");
|
"Unable to prompt user");
|
||||||
}
|
}
|
||||||
if ("ok".equals(msg)) {
|
out.println(msg);
|
||||||
out.println("Message");
|
|
||||||
} else {
|
|
||||||
out.println("fail");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final Thread execThread = new Thread(task);
|
final Thread execThread = new Thread(task, "Task");
|
||||||
execThread.start();
|
execThread.start();
|
||||||
try {
|
try {
|
||||||
execThread.join(100);
|
execThread.join(100);
|
||||||
@@ -55,14 +54,103 @@ public class ForkTaskTest {
|
|||||||
|
|
||||||
try (PipedConsoleOutput pco = new PipedConsoleOutput();
|
try (PipedConsoleOutput pco = new PipedConsoleOutput();
|
||||||
PipedConsoleInput pci = new PipedConsoleInput(null)) {
|
PipedConsoleInput pci = new PipedConsoleInput(null)) {
|
||||||
pci.type("ok");
|
|
||||||
while (!pco.available()) {
|
while (!pco.available()) {
|
||||||
|
pci.type("ok");
|
||||||
task.join(pco, pci, 1000);
|
task.join(pco, pci, 1000);
|
||||||
}
|
}
|
||||||
assertEquals("Execution should work", "Message", pco.readNextLine());
|
assertEquals("Positive execution", "ok", pco.readNextLine());
|
||||||
}
|
}
|
||||||
assertFalse("Running state should be updated by task on its completion",
|
assertFalse("Running state should be updated by task on its completion",
|
||||||
task.isRunning());
|
task.isRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTaskInterruption() throws IOException, InterruptedException {
|
||||||
|
final ForkTask task = new ForkTask(5) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "name";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() throws CommandRunException {
|
||||||
|
while (isRunning()) {
|
||||||
|
String msg;
|
||||||
|
try {
|
||||||
|
msg = in.prompt(1000);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new CommandRunException(CommandRunExceptionType.INTERACTION,
|
||||||
|
"Unable to prompt user");
|
||||||
|
}
|
||||||
|
if (msg != null) {
|
||||||
|
out.println(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final Thread execThread = new Thread(task, "Task");
|
||||||
|
execThread.start();
|
||||||
|
execThread.join(100);
|
||||||
|
|
||||||
|
final AtomicBoolean interrupted = new AtomicBoolean(false);
|
||||||
|
final AtomicBoolean interrupted2 = new AtomicBoolean(false);
|
||||||
|
final InterruptionListener listener = new InterruptionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interrupted() {
|
||||||
|
interrupted.set(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final InterruptionListener listener2 = new InterruptionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void interrupted() {
|
||||||
|
interrupted2.set(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
task.addInterruptionListener(listener);
|
||||||
|
task.addInterruptionListener(listener2);
|
||||||
|
task.rmInterruptionListener(listener2);
|
||||||
|
|
||||||
|
assertFalse("Interruption should not be notified before actual interruption",
|
||||||
|
interrupted.get());
|
||||||
|
assertTrue("Task should be started", task.isStarted());
|
||||||
|
task.setRunning(false);
|
||||||
|
try (PipedConsoleOutput pco = new PipedConsoleOutput();
|
||||||
|
PipedConsoleInput pci = new PipedConsoleInput(null)) {
|
||||||
|
task.join(pco, pci, 2000);
|
||||||
|
}
|
||||||
|
execThread.join();
|
||||||
|
assertTrue("Interruption should be notified to listeners", interrupted.get());
|
||||||
|
|
||||||
|
assertFalse("Running state should be updated by task on its completion",
|
||||||
|
task.isRunning());
|
||||||
|
assertFalse("Interruption should not be notified to removed listeners",
|
||||||
|
interrupted2.get());
|
||||||
|
|
||||||
|
task.rmInterruptionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailingTask() throws InterruptedException {
|
||||||
|
final ForkTask task = new ForkTask(5) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "name";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRun() throws CommandRunException {
|
||||||
|
throw new CommandRunException("Error");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final Thread execThread = new Thread(task, "Task");
|
||||||
|
execThread.start();
|
||||||
|
execThread.join();
|
||||||
|
assertNotNull("Exception should be forwarded", task.getException());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import net.bigeon.gclc.exception.CommandRunException;
|
import net.bigeon.gclc.exception.CommandRunException;
|
||||||
import net.bigeon.gclc.exception.CommandRunExceptionType;
|
import net.bigeon.gclc.exception.CommandRunExceptionType;
|
||||||
|
import net.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
import net.bigeon.gclc.process.mocks.TaskMock;
|
import net.bigeon.gclc.process.mocks.TaskMock;
|
||||||
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
|
||||||
|
|
||||||
/** @author Emmanuel Bigeon */
|
/** @author Emmanuel Bigeon */
|
||||||
public class ProcessListTest {
|
public class ProcessListTest {
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.io.PipedInputStream;
|
import java.io.PipedInputStream;
|
||||||
import java.io.PipedOutputStream;
|
import java.io.PipedOutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -13,9 +15,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import net.bigeon.gclc.manager.PipedConsoleInput;
|
||||||
|
import net.bigeon.gclc.manager.StreamConsoleInput;
|
||||||
import net.bigeon.gclc.tools.ConstantString;
|
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.ATestRunnable;
|
||||||
import net.bigeon.test.junitmt.FunctionalTestRunnable;
|
import net.bigeon.test.junitmt.FunctionalTestRunnable;
|
||||||
import net.bigeon.test.junitmt.TestFunction;
|
import net.bigeon.test.junitmt.TestFunction;
|
||||||
@@ -81,10 +83,28 @@ public class ConnectingConsoleInputTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply() throws Exception {
|
public void apply() throws Exception {
|
||||||
assertNull("Interrupted should return null", in.prompt("m1", -1));
|
try {
|
||||||
assertNull("Interrupted should return null", in.prompt("m2", 5000));
|
final String res = in.prompt("m1", -1);
|
||||||
ended.set(true);
|
fail("interruption of infinite waiting prompt should cause error, but was "
|
||||||
assertNull("Overtime should return null", in.prompt("m3", 200));
|
+ res);
|
||||||
|
} catch (final InterruptedIOException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final String res = in.prompt("m2", 25000);
|
||||||
|
fail("interruption of finite waiting prompt should cause error, but was "
|
||||||
|
+ res);
|
||||||
|
} catch (final InterruptedIOException e) {
|
||||||
|
// ok
|
||||||
|
}
|
||||||
|
synchronized (ended) {
|
||||||
|
ended.set(true);
|
||||||
|
try {
|
||||||
|
assertNull("Overtime should return null", in.prompt("m3", 200));
|
||||||
|
} catch (final InterruptedIOException e) {
|
||||||
|
fail("Unexpected interruption error in overtime");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
final ATestRunnable runnable = new FunctionalTestRunnable(one);
|
final ATestRunnable runnable = new FunctionalTestRunnable(one);
|
||||||
@@ -95,12 +115,16 @@ public class ConnectingConsoleInputTest {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (!ended.get()) {
|
while (!ended.get()) {
|
||||||
try {
|
try {
|
||||||
th.join(500);
|
th.join(100);
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
in.interruptPrompt();
|
synchronized (ended) {
|
||||||
|
if (!ended.get()) {
|
||||||
|
in.interruptPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -112,7 +136,7 @@ public class ConnectingConsoleInputTest {
|
|||||||
|
|
||||||
final PipedOutputStream os = new PipedOutputStream();
|
final PipedOutputStream os = new PipedOutputStream();
|
||||||
final PipedInputStream pis = new PipedInputStream(os);
|
final PipedInputStream pis = new PipedInputStream(os);
|
||||||
in.connect(new StreamConsoleInput(System.out, pis, StandardCharsets.UTF_8));
|
in.connect(new StreamConsoleInput(null, pis, StandardCharsets.UTF_8));
|
||||||
final ATestRunnable runnable2 = new FunctionalTestRunnable(one);
|
final ATestRunnable runnable2 = new FunctionalTestRunnable(one);
|
||||||
final Thread th2 = new Thread(runnable2);
|
final Thread th2 = new Thread(runnable2);
|
||||||
final Thread inter2 = new Thread(new Runnable() {
|
final Thread inter2 = new Thread(new Runnable() {
|
||||||
@@ -121,12 +145,16 @@ public class ConnectingConsoleInputTest {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (!ended.get()) {
|
while (!ended.get()) {
|
||||||
try {
|
try {
|
||||||
th2.join(500);
|
th2.join(100);
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
in.interruptPrompt();
|
synchronized (ended) {
|
||||||
|
if (!ended.get()) {
|
||||||
|
in.interruptPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
import net.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
public class ConnectingConsoleOutputTest {
|
public class ConnectingConsoleOutputTest {
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.bigeon</groupId>
|
<groupId>net.bigeon</groupId>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>2.0.12</version>
|
<version>2.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.bigeon</groupId>
|
<groupId>net.bigeon</groupId>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import java.io.IOException;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import net.bigeon.gclc.exception.CommandRunException;
|
import net.bigeon.gclc.exception.CommandRunException;
|
||||||
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
import net.bigeon.gclc.manager.PipedConsoleOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.bigeon</groupId>
|
<groupId>net.bigeon</groupId>
|
||||||
<artifactId>collections</artifactId>
|
<artifactId>collections</artifactId>
|
||||||
<version>1.1.6</version>
|
<version>1.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
|
|||||||
@@ -38,103 +38,14 @@ package net.bigeon.gclc.swt;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
import org.eclipse.swt.widgets.Widget;
|
|
||||||
|
|
||||||
import net.bigeon.gclc.utils.AOutputForwardRunnable;
|
import net.bigeon.gclc.swt.tools.ToSWTConsoleForwardRunnable;
|
||||||
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
||||||
|
|
||||||
/** The manager for console output to insert in a text.
|
/** The manager for console output to insert in a text.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
public final class ConsoleOutputManager implements ConsoleOutputDisplay {
|
public final class ConsoleOutputManager implements ConsoleOutputDisplay {
|
||||||
/** A runnable appending text to the content of a {@link Text} component.
|
|
||||||
*
|
|
||||||
* @author Emmanuel Bigeon */
|
|
||||||
private static class TextAppendingRunnable implements Runnable {
|
|
||||||
/** The text to append on a line (possibly new). */
|
|
||||||
private final String next;
|
|
||||||
/** The {@link Text} component. */
|
|
||||||
private final Text text;
|
|
||||||
|
|
||||||
/** Create the appending runnable.
|
|
||||||
*
|
|
||||||
* @param text the component to update
|
|
||||||
* @param next the text to append */
|
|
||||||
public TextAppendingRunnable(final Text text, final String next) {
|
|
||||||
this.text = text;
|
|
||||||
this.next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see java.lang.Runnable#run() */
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
final String initialText = text.getText();
|
|
||||||
if (initialText != null && !initialText.isEmpty()) {
|
|
||||||
text.append(System.lineSeparator());
|
|
||||||
}
|
|
||||||
text.append(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The local implementation of the forwarding runnable.
|
|
||||||
*
|
|
||||||
* @author Emmanuel Bigeon */
|
|
||||||
private static final class ToSWTConsoleForwardRunnable
|
|
||||||
extends AOutputForwardRunnable {
|
|
||||||
/** The running status. */
|
|
||||||
private boolean running = true;
|
|
||||||
/** The console output. */
|
|
||||||
private final PipedConsoleOutput out;
|
|
||||||
/** The console output display. */
|
|
||||||
private final ConsoleOutputDisplay display;
|
|
||||||
/** The actual SWT component. */
|
|
||||||
private final Widget element;
|
|
||||||
|
|
||||||
/** Create the forwarding runnable.
|
|
||||||
*
|
|
||||||
* @param manager the manager
|
|
||||||
* @param display the display
|
|
||||||
* @param element the composite */
|
|
||||||
public ToSWTConsoleForwardRunnable(final PipedConsoleOutput manager,
|
|
||||||
final ConsoleOutputDisplay display,
|
|
||||||
final Widget element) {
|
|
||||||
super(manager);
|
|
||||||
out = manager;
|
|
||||||
this.display = display;
|
|
||||||
this.element = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see
|
|
||||||
* net.bigeon.gclc.utils.AOutputForwardRunnable#forwardLine(java.lang.String) */
|
|
||||||
@Override
|
|
||||||
protected void forwardLine(final String m) {
|
|
||||||
display.appendLine(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see net.bigeon.gclc.utils.AOutputForwardRunnable#isRunning() */
|
|
||||||
@Override
|
|
||||||
protected boolean isRunning() {
|
|
||||||
return running && !element.isDisposed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set the running status.
|
|
||||||
*
|
|
||||||
* @param running the running to set */
|
|
||||||
public void setRunning(final boolean running) {
|
|
||||||
this.running = running;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the output.
|
|
||||||
*
|
|
||||||
* @return the currently forwarded output */
|
|
||||||
public PipedConsoleOutput getOuput() {
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The SWT component displaying the output content. */
|
/** The SWT component displaying the output content. */
|
||||||
private final Text text;
|
private final Text text;
|
||||||
/** The forwarding runnable. */
|
/** The forwarding runnable. */
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ import java.io.BufferedReader;
|
|||||||
|
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
|
||||||
|
import net.bigeon.gclc.swt.tools.PromptReadingRunnable;
|
||||||
|
|
||||||
/** The manager for the console prompt updates.
|
/** The manager for the console prompt updates.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bigeon */
|
* @author Emmanuel Bigeon */
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ import org.eclipse.swt.SWT;
|
|||||||
import org.eclipse.swt.events.KeyAdapter;
|
import org.eclipse.swt.events.KeyAdapter;
|
||||||
import org.eclipse.swt.events.KeyEvent;
|
import org.eclipse.swt.events.KeyEvent;
|
||||||
|
|
||||||
import net.bigeon.collections.ArrayRibbon;
|
|
||||||
import net.bigeon.collections.Ribbon;
|
import net.bigeon.collections.Ribbon;
|
||||||
|
import net.bigeon.collections.ribbon.ArrayRibbon;
|
||||||
|
|
||||||
/** A key listener to validate commands and manage the history of commands.
|
/** A key listener to validate commands and manage the history of commands.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package net.bigeon.gclc.swt;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
|
/** A runnable appending text to the content of a {@link Text} component.
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bigeon */
|
||||||
|
public class TextAppendingRunnable implements Runnable {
|
||||||
|
/** The text to append on a line (possibly new). */
|
||||||
|
private final String next;
|
||||||
|
/** The {@link Text} component. */
|
||||||
|
private final Text text;
|
||||||
|
|
||||||
|
/** Create the appending runnable.
|
||||||
|
*
|
||||||
|
* @param text the component to update
|
||||||
|
* @param next the text to append */
|
||||||
|
public TextAppendingRunnable(final Text text, final String next) {
|
||||||
|
this.text = text;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Runnable#run() */
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final String initialText = text.getText();
|
||||||
|
if (initialText != null && !initialText.isEmpty()) {
|
||||||
|
text.append(System.lineSeparator());
|
||||||
|
}
|
||||||
|
text.append(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package net.bigeon.gclc.swt;
|
package net.bigeon.gclc.swt.tools;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package net.bigeon.gclc.swt.tools;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Widget;
|
||||||
|
|
||||||
|
import net.bigeon.gclc.swt.ConsoleOutputDisplay;
|
||||||
|
import net.bigeon.gclc.utils.AOutputForwardRunnable;
|
||||||
|
import net.bigeon.gclc.utils.PipedConsoleOutput;
|
||||||
|
|
||||||
|
/** The local implementation of the forwarding runnable.
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bigeon */
|
||||||
|
public final class ToSWTConsoleForwardRunnable
|
||||||
|
extends AOutputForwardRunnable {
|
||||||
|
/** The running status. */
|
||||||
|
private boolean running = true;
|
||||||
|
/** The console output. */
|
||||||
|
private final PipedConsoleOutput out;
|
||||||
|
/** The console output display. */
|
||||||
|
private final ConsoleOutputDisplay display;
|
||||||
|
/** The actual SWT component. */
|
||||||
|
private final Widget element;
|
||||||
|
|
||||||
|
/** Create the forwarding runnable.
|
||||||
|
*
|
||||||
|
* @param manager the manager
|
||||||
|
* @param display the display
|
||||||
|
* @param element the composite */
|
||||||
|
public ToSWTConsoleForwardRunnable(final PipedConsoleOutput manager,
|
||||||
|
final ConsoleOutputDisplay display,
|
||||||
|
final Widget element) {
|
||||||
|
super(manager);
|
||||||
|
out = manager;
|
||||||
|
this.display = display;
|
||||||
|
this.element = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see
|
||||||
|
* net.bigeon.gclc.utils.AOutputForwardRunnable#forwardLine(java.lang.String) */
|
||||||
|
@Override
|
||||||
|
protected void forwardLine(final String m) {
|
||||||
|
display.appendLine(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see net.bigeon.gclc.utils.AOutputForwardRunnable#isRunning() */
|
||||||
|
@Override
|
||||||
|
protected boolean isRunning() {
|
||||||
|
return running && !element.isDisposed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the running status.
|
||||||
|
*
|
||||||
|
* @param running the running to set */
|
||||||
|
public void setRunning(final boolean running) {
|
||||||
|
this.running = running;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the output.
|
||||||
|
*
|
||||||
|
* @return the currently forwarded output */
|
||||||
|
public PipedConsoleOutput getOuput() {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/** Tool classes for the library. External code should not rely on classes in
|
||||||
|
* there as they can be removed without notice.
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bigeon */
|
||||||
|
package net.bigeon.gclc.swt.tools;
|
||||||
|
|
||||||
@@ -53,6 +53,8 @@ import org.junit.Test;
|
|||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import net.bigeon.gclc.swt.tools.PromptReadingRunnable;
|
||||||
|
|
||||||
/** @author Emmanuel Bigeon */
|
/** @author Emmanuel Bigeon */
|
||||||
public class PromptReadingRunnableTest {
|
public class PromptReadingRunnableTest {
|
||||||
private final Label view = mock(Label.class);
|
private final Label view = mock(Label.class);
|
||||||
@@ -72,7 +74,7 @@ public class PromptReadingRunnableTest {
|
|||||||
}).when(display).syncExec(any(Runnable.class));
|
}).when(display).syncExec(any(Runnable.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test method for {@link net.bigeon.gclc.swt.PromptReadingRunnable#run()}.
|
/** Test method for {@link net.bigeon.gclc.swt.tools.PromptReadingRunnable#run()}.
|
||||||
*
|
*
|
||||||
* @throws IOException if an error occurred */
|
* @throws IOException if an error occurred */
|
||||||
@Test
|
@Test
|
||||||
@@ -85,7 +87,7 @@ public class PromptReadingRunnableTest {
|
|||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test method for {@link net.bigeon.gclc.swt.PromptReadingRunnable#run()}.
|
/** Test method for {@link net.bigeon.gclc.swt.tools.PromptReadingRunnable#run()}.
|
||||||
*
|
*
|
||||||
* @throws IOException if an error occurred */
|
* @throws IOException if an error occurred */
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
<groupId>net.bigeon</groupId>
|
<groupId>net.bigeon</groupId>
|
||||||
<artifactId>gclc</artifactId>
|
<artifactId>gclc</artifactId>
|
||||||
<version>2.1.0</version>
|
<version>2.1.1-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>Generic Command Ligne console</name>
|
<name>Generic Command Ligne console</name>
|
||||||
<description>A generic framework for console applications, with customized command input and output streams.</description>
|
<description>A generic framework for console applications, with customized command input and output streams.</description>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</developers>
|
</developers>
|
||||||
<scm>
|
<scm>
|
||||||
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
<developerConnection>scm:git:gogs@git.code.bigeon.net:emmanuel/gclc.git</developerConnection>
|
||||||
<tag>gclc-2.1.0</tag>
|
<tag>HEAD</tag>
|
||||||
</scm>
|
</scm>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|||||||
Reference in New Issue
Block a user