Fixed issues with buffering input. Now fixed for windows/posix/unsupported
This commit is contained in:
parent
3756df22ab
commit
25855ae04d
|
@ -109,52 +109,70 @@ public class InputConsole {
|
||||||
private final Object inputLockSingle = new Object();
|
private final Object inputLockSingle = new Object();
|
||||||
private final Object inputLockLine = new Object();
|
private final Object inputLockLine = new Object();
|
||||||
|
|
||||||
private final ObjectPool<ByteBuffer2> pool = ObjectPoolFactory.create(new ByteBuffer2Poolable());
|
private final ObjectPool<ByteBuffer2> pool;
|
||||||
private ThreadLocal<ObjectPoolHolder<ByteBuffer2>> threadBuffer = new ThreadLocal<ObjectPoolHolder<ByteBuffer2>>();
|
|
||||||
private List<ObjectPoolHolder<ByteBuffer2>> threadBuffersForRead = new CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>>();
|
private ThreadLocal<ObjectPoolHolder<ByteBuffer2>> readBuff = new ThreadLocal<ObjectPoolHolder<ByteBuffer2>>();
|
||||||
|
private List<ObjectPoolHolder<ByteBuffer2>> readBuffers = new CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>>();
|
||||||
|
private ThreadLocal<Integer> threadBufferCounter = new ThreadLocal<Integer>();
|
||||||
|
|
||||||
|
private ThreadLocal<ObjectPoolHolder<ByteBuffer2>> readLineBuff = new ThreadLocal<ObjectPoolHolder<ByteBuffer2>>();
|
||||||
|
private List<ObjectPoolHolder<ByteBuffer2>> readLineBuffers = new CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>>();
|
||||||
|
|
||||||
private volatile int readChar = -1;
|
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
|
|
||||||
private InputConsole() {
|
private InputConsole() {
|
||||||
Logger logger = InputConsole.logger;
|
Logger logger = InputConsole.logger;
|
||||||
|
|
||||||
|
String readers = System.getProperty(TerminalType.READERS);
|
||||||
|
int readers2 = 32;
|
||||||
|
if (readers != null) {
|
||||||
|
try {
|
||||||
|
readers2 = Integer.parseInt(readers);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.pool = ObjectPoolFactory.create(new ByteBuffer2Poolable(), readers2);
|
||||||
|
|
||||||
|
|
||||||
String type = System.getProperty(TerminalType.TYPE, TerminalType.AUTO).toLowerCase();
|
String type = System.getProperty(TerminalType.TYPE, TerminalType.AUTO).toLowerCase();
|
||||||
if ("dumb".equals(System.getenv("TERM"))) {
|
if ("dumb".equals(System.getenv("TERM"))) {
|
||||||
type = TerminalType.NONE;
|
type = TerminalType.NONE;
|
||||||
logger.debug("$TERM=dumb; setting type={}", type);
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace("System environment 'TERM'=dumb, creating type=" + type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace("Creating terminal, type=" + type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Creating terminal; type={}", type);
|
|
||||||
|
|
||||||
|
|
||||||
String encoding = Encoding.get();
|
|
||||||
Terminal t;
|
Terminal t;
|
||||||
try {
|
try {
|
||||||
if (type.equals(TerminalType.UNIX)) {
|
if (type.equals(TerminalType.UNIX)) {
|
||||||
t = new UnixTerminal(encoding);
|
t = new UnixTerminal();
|
||||||
}
|
}
|
||||||
else if (type.equals(TerminalType.WIN) || type.equals(TerminalType.WINDOWS)) {
|
else if (type.equals(TerminalType.WIN) || type.equals(TerminalType.WINDOWS)) {
|
||||||
t = new WindowsTerminal();
|
t = new WindowsTerminal();
|
||||||
}
|
}
|
||||||
else if (type.equals(TerminalType.NONE) || type.equals(TerminalType.OFF) || type.equals(TerminalType.FALSE)) {
|
else if (type.equals(TerminalType.NONE) || type.equals(TerminalType.OFF) || type.equals(TerminalType.FALSE)) {
|
||||||
t = new UnsupportedTerminal(encoding);
|
t = new UnsupportedTerminal();
|
||||||
} else {
|
} else {
|
||||||
if (isIDEAutoDetect()) {
|
if (isIDEAutoDetect()) {
|
||||||
logger.debug("Terminal is in UNSUPPORTED (best guess). Unable to support single key input. Only line input available.");
|
logger.debug("Terminal is in UNSUPPORTED (best guess). Unable to support single key input. Only line input available.");
|
||||||
t = new UnsupportedTerminal(encoding);
|
t = new UnsupportedTerminal();
|
||||||
} else {
|
} else {
|
||||||
if (OS.isWindows()) {
|
if (OS.isWindows()) {
|
||||||
t = new WindowsTerminal();
|
t = new WindowsTerminal();
|
||||||
} else {
|
} else {
|
||||||
t = new UnixTerminal(encoding);
|
t = new UnixTerminal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
logger.error("Failed to construct terminal, falling back to unsupported");
|
logger.error("Failed to construct terminal, falling back to unsupported");
|
||||||
t = new UnsupportedTerminal(encoding);
|
t = new UnsupportedTerminal();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -162,7 +180,7 @@ public class InputConsole {
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
logger.error("Terminal initialization failed, falling back to unsupported");
|
logger.error("Terminal initialization failed, falling back to unsupported");
|
||||||
t = new UnsupportedTerminal(encoding);
|
t = new UnsupportedTerminal();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
t.init();
|
t.init();
|
||||||
|
@ -174,7 +192,7 @@ public class InputConsole {
|
||||||
t.setEchoEnabled(true);
|
t.setEchoEnabled(true);
|
||||||
|
|
||||||
this.terminal = t;
|
this.terminal = t;
|
||||||
logger.debug("Created Terminal: {} ({}x{})", this.terminal.getClass().getSimpleName(), t.getWidth(), t.getHeight());
|
logger.debug("Created Terminal: {} ({}x{})", t.getClass().getSimpleName(), t.getWidth(), t.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
// called when the JVM is shutting down.
|
// called when the JVM is shutting down.
|
||||||
|
@ -208,15 +226,41 @@ public class InputConsole {
|
||||||
|
|
||||||
/** return -1 if no data or bunged-up */
|
/** return -1 if no data or bunged-up */
|
||||||
private final int read0() {
|
private final int read0() {
|
||||||
synchronized (this.inputLockSingle) {
|
Integer bufferCounter = this.threadBufferCounter.get();
|
||||||
try {
|
ObjectPoolHolder<ByteBuffer2> objectPoolHolder = this.readBuff.get();
|
||||||
this.inputLockSingle.wait();
|
ByteBuffer2 buffer = null;
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return -1;
|
if (objectPoolHolder == null) {
|
||||||
|
bufferCounter = 0;
|
||||||
|
this.threadBufferCounter.set(bufferCounter);
|
||||||
|
|
||||||
|
ObjectPoolHolder<ByteBuffer2> holder = this.pool.take();
|
||||||
|
buffer = holder.getValue();
|
||||||
|
this.readBuff.set(holder);
|
||||||
|
this.readBuffers.add(holder);
|
||||||
|
} else {
|
||||||
|
buffer = objectPoolHolder.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferCounter == buffer.position()) {
|
||||||
|
synchronized (this.inputLockSingle) {
|
||||||
|
buffer.setPosition(0);
|
||||||
|
this.threadBufferCounter.set(0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.inputLockSingle.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.readChar;
|
bufferCounter = this.threadBufferCounter.get();
|
||||||
|
char c = buffer.readChar(bufferCounter);
|
||||||
|
bufferCounter += 2;
|
||||||
|
|
||||||
|
this.threadBufferCounter.set(bufferCounter);
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return empty char[] if no data */
|
/** return empty char[] if no data */
|
||||||
|
@ -237,12 +281,12 @@ public class InputConsole {
|
||||||
// the current line info.
|
// the current line info.
|
||||||
|
|
||||||
// the threadBufferForRead getting added is the part that is important
|
// the threadBufferForRead getting added is the part that is important
|
||||||
if (this.threadBuffer.get() == null) {
|
if (this.readLineBuff.get() == null) {
|
||||||
ObjectPoolHolder<ByteBuffer2> holder = this.pool.take();
|
ObjectPoolHolder<ByteBuffer2> holder = this.pool.take();
|
||||||
this.threadBuffer.set(holder);
|
this.readLineBuff.set(holder);
|
||||||
this.threadBuffersForRead.add(holder);
|
this.readLineBuffers.add(holder);
|
||||||
} else {
|
} else {
|
||||||
this.threadBuffer.get().getValue().clear();
|
this.readLineBuff.get().getValue().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +298,7 @@ public class InputConsole {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPoolHolder<ByteBuffer2> objectPoolHolder = this.threadBuffer.get();
|
ObjectPoolHolder<ByteBuffer2> objectPoolHolder = this.readLineBuff.get();
|
||||||
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
int len = buffer.position();
|
int len = buffer.position();
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
|
@ -267,9 +311,9 @@ public class InputConsole {
|
||||||
// dump the chars in the buffer (safer for passwords, etc)
|
// dump the chars in the buffer (safer for passwords, etc)
|
||||||
buffer.clearSecure();
|
buffer.clearSecure();
|
||||||
|
|
||||||
this.threadBuffersForRead.remove(objectPoolHolder);
|
this.readLineBuffers.remove(objectPoolHolder);
|
||||||
this.pool.release(objectPoolHolder);
|
this.pool.release(objectPoolHolder);
|
||||||
this.threadBuffer.set(null);
|
this.readLineBuff.set(null);
|
||||||
|
|
||||||
return readChars;
|
return readChars;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +346,6 @@ public class InputConsole {
|
||||||
while ((typedChar = this.terminal.read()) != -1) {
|
while ((typedChar = this.terminal.read()) != -1) {
|
||||||
synchronized (this.inputLock) {
|
synchronized (this.inputLock) {
|
||||||
// don't let anyone add a new reader while we are still processing the current actions
|
// don't let anyone add a new reader while we are still processing the current actions
|
||||||
|
|
||||||
asChar = (char) typedChar;
|
asChar = (char) typedChar;
|
||||||
|
|
||||||
if (logger2.isTraceEnabled()) {
|
if (logger2.isTraceEnabled()) {
|
||||||
|
@ -311,22 +354,25 @@ public class InputConsole {
|
||||||
|
|
||||||
// notify everyone waiting for a character.
|
// notify everyone waiting for a character.
|
||||||
synchronized (this.inputLockSingle) {
|
synchronized (this.inputLockSingle) {
|
||||||
if (this.terminal.wasSequence() && typedChar == '\n') {
|
// have to do readChar first (readLine has to deal with \b and \n
|
||||||
// don't want to forward \n if it was a part of a sequence in the unsupported terminal
|
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.readBuffers) {
|
||||||
// the JIT will short-cut this out if we are not the unsupported terminal
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
} else {
|
buffer.writeChar(asChar);
|
||||||
this.readChar = typedChar;
|
|
||||||
this.inputLockSingle.notifyAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.inputLockSingle.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// now to handle readLine stuff
|
||||||
|
|
||||||
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
|
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
|
||||||
if (typedChar == '\b') {
|
if (asChar == '\b') {
|
||||||
int position = 0;
|
int position = 0;
|
||||||
|
|
||||||
// clear ourself + one extra.
|
// clear ourself + one extra.
|
||||||
if (ansiEnabled) {
|
if (ansiEnabled) {
|
||||||
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.threadBuffersForRead) {
|
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.readLineBuffers) {
|
||||||
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
// size of the buffer BEFORE our backspace was typed
|
// size of the buffer BEFORE our backspace was typed
|
||||||
int length = buffer.position();
|
int length = buffer.position();
|
||||||
|
@ -363,21 +409,17 @@ public class InputConsole {
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read-line will ignore backspace
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else if (asChar == '\n') {
|
||||||
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
|
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
|
||||||
if (asChar == '\n') {
|
|
||||||
synchronized (this.inputLockLine) {
|
synchronized (this.inputLockLine) {
|
||||||
this.inputLockLine.notifyAll();
|
this.inputLockLine.notifyAll();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// only append if we are not a new line.
|
// only append if we are not a new line.
|
||||||
// our windows console PREVENTS us from returning '\r' (it truncates '\r\n', and returns just '\n')
|
// our windows console PREVENTS us from returning '\r' (it truncates '\r\n', and returns just '\n')
|
||||||
|
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.readLineBuffers) {
|
||||||
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.threadBuffersForRead) {
|
|
||||||
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
buffer.writeChar(asChar);
|
buffer.writeChar(asChar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,42 +10,12 @@ public abstract class Terminal {
|
||||||
public static final int DEFAULT_HEIGHT = 24;
|
public static final int DEFAULT_HEIGHT = 24;
|
||||||
|
|
||||||
private volatile boolean echoEnabled;
|
private volatile boolean echoEnabled;
|
||||||
private volatile Thread shutdown;
|
|
||||||
|
|
||||||
public Terminal() {
|
public Terminal() {
|
||||||
if (this.shutdown != null) {
|
|
||||||
try {
|
|
||||||
Runtime.getRuntime().removeShutdownHook(this.shutdown);
|
|
||||||
}
|
|
||||||
catch (IllegalStateException e) {
|
|
||||||
// The VM is shutting down, ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register a task to restore the terminal on shutdown
|
|
||||||
Runnable runnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
restore();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Terminal.this.logger.error("Unable to restore the terminal", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.shutdown = new Thread(runnable, "Terminal");
|
|
||||||
|
|
||||||
try {
|
|
||||||
Runtime.getRuntime().addShutdownHook(this.shutdown);
|
|
||||||
}
|
|
||||||
catch (IllegalStateException e) {
|
|
||||||
// The VM is shutting down, ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract void init() throws IOException;
|
public abstract void init() throws IOException;
|
||||||
|
|
||||||
public abstract void restore() throws IOException;
|
public abstract void restore() throws IOException;
|
||||||
|
|
||||||
public void setEchoEnabled(boolean enabled) {
|
public void setEchoEnabled(boolean enabled) {
|
||||||
|
@ -63,11 +33,4 @@ public abstract class Terminal {
|
||||||
* @return a character from whatever underlying input method the terminal has available.
|
* @return a character from whatever underlying input method the terminal has available.
|
||||||
*/
|
*/
|
||||||
public abstract int read();
|
public abstract int read();
|
||||||
|
|
||||||
/**
|
|
||||||
* Only needed for unsupported character input.
|
|
||||||
*/
|
|
||||||
public boolean wasSequence() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package dorkbox.util.input;
|
||||||
|
|
||||||
public class TerminalType {
|
public class TerminalType {
|
||||||
public static final String TYPE = "input.terminal";
|
public static final String TYPE = "input.terminal";
|
||||||
|
public static final String READERS = "input.terminal.readers";
|
||||||
|
|
||||||
public static final String AUTO = "auto";
|
public static final String AUTO = "auto";
|
||||||
public static final String UNIX = "unix";
|
public static final String UNIX = "unix";
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
|
|
||||||
|
import dorkbox.util.input.Encoding;
|
||||||
import dorkbox.util.input.Terminal;
|
import dorkbox.util.input.Terminal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,7 +26,8 @@ public class UnixTerminal extends Terminal {
|
||||||
private ByteBuffer windowSizeBuffer = ByteBuffer.allocate(8);
|
private ByteBuffer windowSizeBuffer = ByteBuffer.allocate(8);
|
||||||
|
|
||||||
|
|
||||||
public UnixTerminal(String encoding) throws Exception {
|
public UnixTerminal() throws Exception {
|
||||||
|
String encoding = Encoding.get();
|
||||||
this.reader = new InputStreamReader(System.in, encoding);
|
this.reader = new InputStreamReader(System.in, encoding);
|
||||||
|
|
||||||
this.term = (PosixTerminalControl) Native.loadLibrary("c", PosixTerminalControl.class);
|
this.term = (PosixTerminalControl) Native.loadLibrary("c", PosixTerminalControl.class);
|
||||||
|
|
|
@ -1,29 +1,20 @@
|
||||||
package dorkbox.util.input.unsupported;
|
package dorkbox.util.input.unsupported;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import dorkbox.util.bytes.ByteBuffer2;
|
import dorkbox.util.bytes.ByteBuffer2;
|
||||||
import dorkbox.util.input.Terminal;
|
import dorkbox.util.input.Terminal;
|
||||||
import dorkbox.util.input.posix.InputStreamReader;
|
|
||||||
|
|
||||||
public class UnsupportedTerminal extends Terminal {
|
public class UnsupportedTerminal extends Terminal {
|
||||||
|
|
||||||
private final ByteBuffer2 buffer = new ByteBuffer2(8, -1);
|
private ByteBuffer2 buffer = new ByteBuffer2(8, -1);
|
||||||
|
|
||||||
private BufferedReader reader;
|
private int readerCount = -1;
|
||||||
private String readLine = null;
|
private InputStream in;
|
||||||
private char[] line;
|
|
||||||
|
|
||||||
private ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
|
public UnsupportedTerminal() {
|
||||||
@Override
|
this.in = System.in;
|
||||||
protected Integer initialValue() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public UnsupportedTerminal(String encoding) {
|
|
||||||
this.reader = new BufferedReader(new InputStreamReader(System.in, encoding));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,46 +37,39 @@ public class UnsupportedTerminal extends Terminal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int read() {
|
public final int read() {
|
||||||
// if we are reading data (because we are in IDE mode), we want to return ALL
|
// if we are reading data (because we are in IDE mode), we want to return ALL the chars of the line!
|
||||||
// the chars of the line!
|
|
||||||
|
|
||||||
// so, readChar is REALLY the index at which we return letters (until the whole string is returned)
|
|
||||||
int readerCount = this.indexOfStringForReadChar.get();
|
|
||||||
|
|
||||||
if (readerCount == -1) {
|
|
||||||
|
|
||||||
|
// so, 'readerCount' is REALLY the index at which we return letters (until the whole string is returned)
|
||||||
|
if (this.readerCount == -1) {
|
||||||
// we have to wait for more data.
|
// we have to wait for more data.
|
||||||
try {
|
try {
|
||||||
this.readLine = this.reader.readLine();
|
InputStream sysIn = this.in;
|
||||||
} catch (IOException e) {
|
int read;
|
||||||
return -1;
|
char asChar;
|
||||||
}
|
this.buffer.clearSecure();
|
||||||
|
|
||||||
this.line = this.readLine.toCharArray();
|
while ((read = sysIn.read()) != -1) {
|
||||||
this.buffer.clear();
|
asChar = (char)read;
|
||||||
for (char c : this.line) {
|
if (asChar == '\n') {
|
||||||
this.buffer.writeChar(c);
|
this.readerCount = this.buffer.position();
|
||||||
|
this.buffer.rewind();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
this.buffer.writeChar(asChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
readerCount = 0;
|
|
||||||
this.indexOfStringForReadChar.set(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// EACH thread will have it's own count!
|
// EACH thread will have it's own count!
|
||||||
if (readerCount == this.buffer.position()) {
|
if (this.readerCount == this.buffer.position()) {
|
||||||
this.indexOfStringForReadChar.set(-1);
|
this.readerCount = -1;
|
||||||
return '\n';
|
return '\n';
|
||||||
} else {
|
} else {
|
||||||
this.indexOfStringForReadChar.set(readerCount+2); // because 2 bytes per char in java
|
char c = this.buffer.readChar();
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
char c = this.buffer.readChar(readerCount);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean wasSequence() {
|
|
||||||
return this.line.length > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,14 +7,6 @@ public class ObjectPoolFactory {
|
||||||
private ObjectPoolFactory() {
|
private ObjectPoolFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a pool with the max number of available processors as the pool size (padded by 2x as many).
|
|
||||||
*/
|
|
||||||
public static <T> ObjectPool<T> create(PoolableObject<T> poolableObject) {
|
|
||||||
return create(poolableObject, Runtime.getRuntime().availableProcessors() * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a pool of the specified size
|
* Creates a pool of the specified size
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,8 +11,8 @@ public class ProcessProxy extends Thread {
|
||||||
|
|
||||||
// when reading from the stdin and outputting to the process
|
// when reading from the stdin and outputting to the process
|
||||||
public ProcessProxy(String processName, InputStream inputStreamFromConsole, OutputStream outputStreamToProcess) {
|
public ProcessProxy(String processName, InputStream inputStreamFromConsole, OutputStream outputStreamToProcess) {
|
||||||
is = inputStreamFromConsole;
|
this.is = inputStreamFromConsole;
|
||||||
os = outputStreamToProcess;
|
this.os = outputStreamToProcess;
|
||||||
|
|
||||||
setName(processName);
|
setName(processName);
|
||||||
setDaemon(true);
|
setDaemon(true);
|
||||||
|
@ -20,7 +20,7 @@ public class ProcessProxy extends Thread {
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
is.close();
|
this.is.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,28 +32,26 @@ public class ProcessProxy extends Thread {
|
||||||
// the stream will be closed when the process closes it (usually on exit)
|
// the stream will be closed when the process closes it (usually on exit)
|
||||||
int readInt;
|
int readInt;
|
||||||
|
|
||||||
if (os == null) {
|
if (this.os == null) {
|
||||||
// just read so it won't block.
|
// just read so it won't block.
|
||||||
while ((readInt = is.read()) != -1) {
|
while ((readInt = this.is.read()) != -1) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while ((readInt = is.read()) != -1) {
|
while ((readInt = this.is.read()) != -1) {
|
||||||
os.write(readInt);
|
System.err.println("READ : " + (char)readInt);
|
||||||
|
this.os.write(readInt);
|
||||||
// flush the output on new line. Works for windows/linux, since \n is always the last char in the sequence.
|
// always flush
|
||||||
if (readInt == '\n') {
|
this.os.flush();
|
||||||
os.flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ignore) {
|
} catch (IOException ignore) {
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (os != null) {
|
if (this.os != null) {
|
||||||
os.flush(); // this goes to the console, so we don't want to close it!
|
this.os.flush(); // this goes to the console, so we don't want to close it!
|
||||||
}
|
}
|
||||||
is.close();
|
this.is.close();
|
||||||
} catch (IOException ignore) {
|
} catch (IOException ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user