Java interactive console - java

I'm currently developing a Java command-line application and I want to make it interactive. I mean, I have 2 threads:
one thread is permanently writing some information to stdout
the second thread only reads from stdin and is waiting for some commands from the user
But the point is, it's really annoying when I'm typing a command while the first thread writes something to stdout, the command is "cut".
For example:
I want to type the command 'set infolevel 2', and while I'm typing that, the first thread outputs "some information 1234".
My console output may look like this:
set inf // user typing command into stdin
some information 1234 // first thread writes out information
olevel 2 // continuing reading command from stdin
It would be very awsome if someone could tell me if there's a library/API something like that. Thanks!

I guess you would be using System.out.println for output to the console and new Scanner(System.in); for reading input.
Essentially System.out is a PrintStream and System.in is a InputStream and are different object (and streams) but they both use same source (I guess IDE console or command prompt in your case) so when 2 or more threads will try to use the same source then you will get the behavior you have mentioned because by default same source/console is used by the host environment or user. Read below from Java source:
System.out
/**
* The "standard" input stream. This stream is already
* open and ready to supply input data. Typically this stream
* corresponds to keyboard input or another input source specified by
* the host environment or user.
*/
System.in
/**
* The "standard" output stream. This stream is already
* open and ready to accept output data. Typically this stream
* corresponds to display output or another output destination
* specified by the host environment or user.
As far as I know, there are really no such API's to help you out what you are looking for but there are couple of work around options:
Please note, IMHO Option 3 or any similar solution which is based on synchronization is something which you may not want because it will limit your output'ing capabilities
Option 1:
Configure a different console device and then access it using System.console(). In this case, you will have different sources for read and write to console and hence you will not get what you are seeing. If you don't explicitly configure anything then by default you will get System.console() as NULL
Option 2:
Instead of writing the output to console, use a file to write the output. This will ensure that your input and output stream are not messing up with each other.
Option 3:
If you have same source for both read and write to console, then synchronize the access. Below is same code but please be mindful that you could still see some overlap for the time when object lock is being acquired and released but once lock is acquired or released on System.out or System.in then you will not see overlap.
public class Test {
static Object object = new Object();
public static void main(String[] args) {
new Thread(){
#Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
Date date = new Date();
System.out.println("I am coming from first thread i.e. " + Thread.currentThread().getId() + " : " + date);
}
}
}
}.start();
new Thread(){
#Override
public void run() {
Scanner scanner = new Scanner(System.in);
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
scanner.next();
}
}
}
}.start();
}
}

It seems you need to synchronize the two threads on some kind of object. Something like : private Object lockObject = new Object(); Thread t1 = new Thread() { public void run() {synchronized( lockObject ){ //your code } } };

You could either use locking as svasa suggested in his answer, or modify your code so that you have one thread that does both input and output, and the other thread does the computational work. Use an ArrayBlockingQueue to send the output of the work thread to the I/O thread.

Related

how to read output and provide input to subprocess in java

I want to make a Java program to run another Java program. I wrote some code to run another Java program. Jhon.java is a Java file from which I execute the Add.class file. But there is problem while reading output and provide input to subprocess. I have this code.
import java.io.*;
class Jhon
{
public static void main(String args[])
{
try
{
String command="java Add";
Process proc=Runtime.getRuntime().exec(command);
Thread t1=new A(proc);
t1.start();
Thread t2=new B(proc);
t2.start();
proc.waitFor();
t1.join();
t2.join();
}
catch(Exception e)
{}
}
}
class A extends Thread
{
Process proc;
A(Process proc)
{
this.proc=proc;
}
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try
{
while(true)
{
String s = br.readLine();
OutputStream out = proc.getOutputStream();
out.write(s.getBytes());
out.close();
}
}
catch(Exception e)
{}
}
}
class B extends Thread
{
Process proc;
B(Process proc)
{
this.proc=proc;
}
public void run()
{
try
{
String line="";
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while((line=br.readLine())!=null)
{
System.out.println(line);
}
}
catch(Exception e)
{}
}
}
This is the Add.java file which is executed by Jhon.java file
import java.io.*;
class Add
{
public static void main(String args[])
{
int a,b,c;
try
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter first number");
a=Integer.parseInt(br.readLine());
System.out.println("Enter second number");
b=Integer.parseInt(br.readLine());
c=a+b;
System.out.println("Addition is "+c);
}
catch(IOException e)
{
System.out.println(e);
}
}
}
When I execute the Add.java file from Jhon.java file it asks to enter the first number. After providing the first number, it asks to enter the second number. After providing the second number, it does not print addition. The terminal hangs . So what am I doing wrong? Please give me a solution.
Your class A reads the first line of input, calls getOutputStream() and os.write() to (begin to) send that line to the subprocess and then calls os.close(). After flushing the data, that closes the pipe that communicates to the standard input of the subprocess. It then loops around to read the next line and tries to getOutputStream and write and close again, but the write does nothing because it is buffered and the close actually fails because the pipe is closed but it suppresses the internal exception, I believe so autoclose is safe. It then waits for further input.
Your class Add in the subprocess successfully reads the first line; when it tries to read the second line its standard input (the pipe from the master) has been closed normally, which is considered "EOF" (End Of File). br.readLine() returns null to indicate EOF, but you pass it to Integer.parseInt which causes a NullPointerException, which isn't caught (it's not a subtype of IOException) so the Java default is to display a stacktrace on standard error and exit. Standard error for a subprocess is piped to the master as a separate stream (not "Input" stream) and your master isn't looking at it, so that information is lost.
Meanwhile (the thread for) your class A is still waiting for input. If you enter whatever the end-of-input signal is on your platform (usually control-D on Unix but can be configured to something else, control-Z on Windows) it will treat that as EOF, readLine will return null and so s.getBytes() will throw a NullPointerException which your catch(IOException){} will silently discard, and it will exit with no indication of the numerous problems that actually occurred.
Moral: in addition to trying to write correct code in the first place, realize that humans don't get everything perfect every time, so don't throw away exceptions unless you know for certain what caused them -- and at your stage of learning you don't know. And try not to throw away other error information either (in this case the error stream from the subprocess).
Fixes:
call getOutputStream only once, and for each input line (in the loop if you keep the loop but see next) do os.write(line) and os.flush() but NOT os.close().
either rearrange this to be synchronous as #MadProgrammer commented, or else arrange so that your input-and-send thread t1 terminates when the subprocess exits, or equivalently when the receive-and-display thread t2 terminates -- which it does when br.readLine()==null indicating EOF because the subprocess exited, which class B does test correctly unlike class A. This is hard to do automatically because A is already sitting in readLine which cannot be interrupted, at least not reliably. One simple possibility is to output a message telling the user to now enter the end-of-input signal, and code A to handle EOF correctly.
or, a real kludge but for completeness, make t1 a daemon thread and don't join it. Then main will return which terminates the main thread once the subprocess has exited and t2 has terminated, and the JVM will exit without waiting for t1. Because this is usually a Bad Idea I won't give you 'teh codez' but a little googling will find how to do this.

Java: Object.wait() causes main thread of execution to return from test

I'm in the process of writing some tests to drive development for a side project of mine, and am encountering some very strange Java behavior:
Object.wait() causes the main thread of execution to return and skip all of the following lines of execution, but only the second time it's called in a loop.
The reason I know this is because I'm attempting to write tests without the use of Thread.sleep() because I believe it is generally bad practice to insert these in main threads of execution, especially tests which would later scale and become extremely long-running tasks.
Here is my test:
#Test
public void testSendReceiveAll() throws Exception {
for (String s : (ArrayList<String>)testFiles) {
((FakeSendFileApi) sendFileApi).setSender(new InetSocketAddress(LOCALHOST,
LOCALPORT)).setIncomingFileName(s + incrAppend());
PendingFile pendingFile = new PendingFile(TEST_PATH + s, new InetSocketAddress(LOCALHOST,
LOCALPORT));
SendAction sendAction = new SendAction(pendingFile);
Thread sendActionThread = new Thread(sendAction);
synchronized (sendAction){
sendActionThread.start();
sendAction.wait(TIMEOUT_MS);
}
File file = new File(s + fileAppend);
assertTrue(file.exists());
assertTrue(file.isFile());
assertTrue(file.canRead());
assertTrue(file.delete());
}
}
Explanation of what it does: Iterate over all of the test files and send and receive them all locally. There is a SendAction class which is instantiated and run in the test:
/**
* Attempts to send the specified file to the specified <code>InetSocketAddress</code>.
* The file's path must be specified completely either absolutely or relatively.
*
* #return true if <code>pendingFile</code> was sent successfully in its entirety.
*/
public synchronized void run() {
try {
ServerSocket serverSocket = new ServerSocket(pendingFile.getSender().getPort());
serverSocket.setSoTimeout(socketTimeoutMillis);
// Blocks until a connection is made on specified socket or until TIMEOUT is reached.
Socket socket = serverSocket.accept();
System.out.println("Sending file " + pendingFile.getFileName());
OutputStream outputStream = socket.getOutputStream();
sendByteArray(new RandomAccessFile(pendingFile.getFileName(), "r"), outputStream);
serverSocket.close();
notifyAll();
} catch (IOException e) {
System.err.println(e); // TODO log error appropriately
}
}
The problem: When I hit the synchronized block of the test, and start the thread to send, then wait for a notify from that sendAction, this works the first time in the loop. The second time through however, the test simply passes and exits on the call to
sendAction.wait(TIMEOUT_MS);
This only occurs sometimes, and not others. I have put print statements to see if I can achieve the race condition without debugging and it does send and receive the first file, but doesn't always send and receive the second file. When I put a println() statement just after the sendAction.wait(TIMEOUT_MS); call, it never executes after the second loop iteration.
What gives???
waits should always occur in loops. (Refer to javadoc of Object.wait() for more details).
Maintain a flag to mark the completion of the task and use it in the condition to guard sendAction.wait()
while(!sendAction.finished) {
sendAction.wait(TIMEOUT_MS);
}
set "sendAction.finished" to true before calling the notifyAll()... AND DO THIS IN FINALLY.

how to interrupt a scanner.nextline() call

There are many threads on SO about interrupting reading the system.in but what I am looking for here is some kind of advice as to how to best code what I am trying to achieve.
I have a getlogin() method that needs to do the following: ask a user to input the desired login environnement details, if after 6 seconds user have not input a valid value ("live" or "test") then set userlogin variable to "test" and return it to the caller.
I have taken the following approach for the getlogin() implementation:
launch two threads which do the following:
thread1 creates a scanner object then calls scanner.nextline() and depending on user input set a variable userlogin. Interrupts thread2 before exiting thread1.
thread2 waits 6 seconds and if after that userlogin is still not set, then set a default value for userlogin. Interrupts thread1 before exiting thread2.
join thread2 to stop main Thread from returning userlogin as null
return userlogin
The problem I have with the approach is that scanner.nextline() does not interrupt when thread2 calls thread1.interrupt, which is why I do not join thread1 in step 2 as the main Thread would hang.
Is there a way to get thread1 to complete after thread2 interrupts it? Or else is this approach completely overkill and there is a much simpler way to achieve the contract?
The simplest solution is to expose the underlying stream in the "reading" thread and close that stream from the timeout thread. This should interrupt the reading and raise an exception. Handle this exception and you should be able to proceed with your logic. The only gotcha is that you won't be able to re-use the same stream again. Unfortunately there is no easy way to deal with interruption of blocking system calls.
EDIT:
Following a completely different line of reasoning; given that we can't close the input stream just to interrupt it, the only way I can think of is to use the "programmatic user input" facilities offered by the Robot class. Here is an example which works out for me:
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
public class ConsoleTest {
/**
* #param args
*/
public static void main(String[] args) {
new TimeoutThread().start();
new ReaderThread().start();
}
}
class ReaderThread extends Thread {
#Override
public void run() {
System.out.print("Please enter your name: ");
try(Scanner in = new Scanner(System.in)) {
String name = in.nextLine();
if(name.trim().isEmpty()) {
name = "TEST"; // default user name
}
System.out.println("Name entered = " + name);
}
}
}
class TimeoutThread extends Thread {
#Override
public void run() {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
} catch(Exception e) {
e.printStackTrace();
}
}
}
The above code uses the logic that once that timeout has expired, we simulate a newline which will cause the "name" variable to be blank. Then we have a check which performs the necessary logic and sets the appropriate user name.
The gotcha about the above approach is that it:
Uses Robot class of AWT so might not play well with headless terminals (?)
Assumes that the focus window is the console window. If the focus is somewhere else, the ENTER key-press will be registered for that window as opposed to your application window.
Hope this helps you out. I'm really out of ideas now. :)
Why not just poll with System.in.available() if there are bytes to read? It is non-blocking: one can do the call to Scanner.nextLine(), which is blocking, when sure it works and does not block.
A FutureTask together with a lambda expression can also be used:
FutureTask<String> readNextLine = new FutureTask<String>(() -> {
return scanner.nextLine();
});
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(readNextLine);
try {
String token = readNextLine.get(5000, TimeUnit.MILLISECONDS);
...
} catch (TimeoutException e) {
// handle time out
}
Another version of geri's answer would be:
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> future = executor.submit(() -> {
try (Scanner in = new Scanner(System.in)) {
return in.nextLine();
}
});
try {
return future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e1) {
return ...;
}

In a multithreaded Java program, does each thread have its own copy of System.out?

I'm writing a multithreaded Java program where each thread potentially needs its standard output redirected to a separate file. Each thread would have its own file. Is it possible to redirect System.out on a "per-thread" basis or are changes to System.out global across all threads?
Is it possible to redirect System.out on a "per-thread" basis
No it is not possible. System.out is static and there is one per JVM that is loaded as part of the system classloader when the JVM initially boots. Although of course using proper logging calls per-thread is recommend, I assume there are reasons why you can't do this. Probably a 3rd party library or other code is what is using System.out in this manner.
One thing you could do (as a radical suggestion) is to make your own PrintStream that delegates to a ThreadLocal<PrintStream>. But you will need to #Override the appropriate methods called by your application to get it to work per-thread.
Lastly, if you are asking this because you are worried about concurrency, System.out is a PrintStream so it is already synchronized under the covers and can be used safely by multiple threads.
Is it possible to redirect System.out on a "per-thread" basis
Some developers from Maia Company have provided a public implementation of a PrintStream that provides one "STDOUT" per thread in this article : "Thread Specific System.out".
In their implementation they override only write methods, flush, close and checkError. It seems to be enough in their case.
They did not "need to #Override all of the methods called to get it to work per-thread" as #Gray stated in his answer.
NOTA:
Please find below the original code from Maia.
I found it here on the wayback machine. The original page was removed from the website of Maia. I reproduce it here for the reader's curiosity. I do not provide any support for this code.
Main.java
Creates a ThreadPrintStream, installs it as System.out, and creates and starts 10 threads.
public class Main {
public static void main(String[] args) {
// Call replaceSystemOut which replaces the
// normal System.out with a ThreadPrintStream.
ThreadPrintStream.replaceSystemOut();
// Create and start 10 different threads. Each thread
// will create its own PrintStream and install it into
// the ThreadPrintStream and then write three messages
// to System.out.
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new StreamText());
thread.start();
// Report to the console that a new thread was started.
System.out.println("Created and started " + thread.getName());
}
}
}
StreamText.java
A simple Runnable for each thread that opens a file for the thread’s output and installs it into the ThreadPrintStream.
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
/** A small test class that sets System.out for the currently executing
* thread to a text file and writes three messages to System.out. */
public class StreamText implements Runnable {
#Override
public void run() {
try {
// Create a text file where System.out.println()
// will send its data for this thread.
String name = Thread.currentThread().getName();
FileOutputStream fos = new FileOutputStream(name + ".txt");
// Create a PrintStream that will write to the new file.
PrintStream stream = new PrintStream(new BufferedOutputStream(fos));
// Install the PrintStream to be used as System.out for this thread.
((ThreadPrintStream)System.out).setThreadOut(stream);
// Output three messages to System.out.
System.out.println(name + ": first message");
System.out.println("This is the second message from " + name);
System.out.println(name + ": 3rd message");
// Close System.out for this thread which will
// flush and close this thread's text file.
System.out.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
ThreadPrintStream.java
Extends java.io.PrintStream. An object of ThreadPrintStream replaces the normal System.out and maintains a separate java.io.PrintStream for each thread.
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
/** A ThreadPrintStream replaces the normal System.out and ensures
* that output to System.out goes to a different PrintStream for
* each thread. It does this by using ThreadLocal to maintain a
* PrintStream for each thread. */
public class ThreadPrintStream extends PrintStream {
/** Changes System.out to a ThreadPrintStream which will
* send output to a separate file for each thread. */
public static void replaceSystemOut() {
// Save the existing System.out
PrintStream console = System.out;
// Create a ThreadPrintStream and install it as System.out
ThreadPrintStream threadOut = new ThreadPrintStream();
System.setOut(threadOut);
// Use the original System.out as the current thread's System.out
threadOut.setThreadOut(console);
}
/** Thread specific storage to hold a PrintStream for each thread */
private ThreadLocal<PrintStream> out;
private ThreadPrintStream() {
super(new ByteArrayOutputStream(0));
out = new ThreadLocal<PrintStream>();
}
/** Sets the PrintStream for the currently executing thread. */
public void setThreadOut(PrintStream out) {
this.out.set(out);
}
/** Returns the PrintStream for the currently executing thread. */
public PrintStream getThreadOut() {
return this.out.get();
}
#Override public boolean checkError() {
return getThreadOut().checkError();
}
#Override public void write(byte[] buf, int off, int len) {
getThreadOut().write(buf, off, len);
}
#Override public void write(int b) { getThreadOut().write(b); }
#Override public void flush() { getThreadOut().flush(); }
#Override public void close() { getThreadOut().close(); }
}
You are right but not in the way you think. When a thread uses
System.out.println();
It takes a copy of the reference System.out, but not a copy of the object this references.
This means all threads will normally see the same object for writing to output.
Note: This fields in not thread safe and if you call System.setOut(PrintStream) If you use this there is a potential, undesirable race condition where different threads to have different local copies of System.out. This cannot be used to solve this question.
Is it possible to redirect System.out on a "per-thread" basis
You can do this by replacing System.out with your own implementation which is thread specific. i.e. a sub class of PrintStream. I have done this for logging where I wanted each thread's output to be consistent and not interleaved. e.g. Imagine printing two stack traces in two threads at the same time. ;)
System.out is static, and therefore the same instance is shared between all threads.
Is it possible to redirect System.out on a "per-thread" basis
You can redirect them all to your delegate which will be responsible for 'per-thread' logic.
Here is example of parallel JBehave tests having theirs own file output.

Java console output from another thread dropped

I have a problem with the console output of one of my threads being dropped (in Java). The situation is as follows: I spawn a thread that listens (using a blocking method) for incoming messages. These messages are then asynchronously written to the console. Meanwhile, I read in the user input on the console via System.console().readLine().
The problem is that the text is never written to the console at all. I mean, as the readLine() method is blocking, I would have expected the console at least to show the output that has been written to the console as soon as something is entered in the main thread.. Or am I missing the point here?
The relevant source is
// ...
// handle receiving messages
(new Thread() {
#Override
public void run() {
while (executing) received(new String(subSocket.recv(0)));
}
}).start();
// ...
String input;
try {
while ((input = System.console().readLine()) != null && !input.equals(".")) {
pubSocket.send(input.getBytes(), 0);
Thread.yield();
}
}
catch (Exception ex) { }
finally {executing = false;}
And the received method is
public void received(String s) {
System.console().format("(%s)", s);
System.console().flush();
}
What am I doing wrong? Or is there a better way to do this? I mean, I tried to use a BufferedReader encapsulating the input stream in order to read it linewise and used System.out.format() along with it.. To the same effect - Nothing :(.
Cheers,
fxx
Try something like,
Implement a thread to read from input and store it in synchronized map/vector/list etc..
Another thread is listening on that collection, which will then process the message.
I think this should help in some way... Main thing is, don't run the loop on system input. Give it a try.

Categories

Resources